# Dify Chatflow 提示词定义 ## 1. 概述 本文档定义数字能量学智能体 Dify Chatflow 工作流的完整配置,包括系统提示词、输入架构、输出格式和节点配置。 **用途:** 用户在微信小程序中生成能量盘后,向 AI 提问获得数字能量学专业解读。 **知识库集成:** Chatflow 在 LLM 节点之前插入**知识检索节点**,从 Dify 知识库(ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`)中动态检索与用户问题相关的命理知识,将检索结果注入 LLM 上下文,实现 RAG(检索增强生成)。 **数据流:** 小程序 → 后端 API → Dify Chatflow → 知识检索(RAG)→ LLM 解读 → 返回用户 --- ## 2. 输入架构 ### 2.1 Dify API 调用格式 后端 `DifyService.java` 调用 Dify API: ``` POST /v1/chat-messages Authorization: Bearer {api_key} Content-Type: application/json { "inputs": { "chart_context": "{...chart JSON...}" }, "query": "请解读我的主性格", "user": "user_12345" } ``` ### 2.2 chart_context JSON 格式 后端传入的 `chart_context` 字段包含完整的能量盘数据,格式如下: ```json { "positions": { "A": 2, "B": 0, "C": 9, "D": 5, "E": 8, "F": 2, "G": 9, "H": 5, "I": 4, "J": 11, "K": 5, "L": 9, "M": 7, "N": 5, "O": 3 }, "zones": { "mainCharacter": { "name": "主性格", "positions": ["O"], "values": [3] }, "fatherSource": { "name": "父源区", "positions": ["I", "J"], "values": [4, 11] }, "motherSource": { "name": "母源区", "positions": ["K", "L"], "values": [5, 9] }, "leftZone": { "name": "左区(0-20岁)", "positions": ["A", "F", "I", "O"], "values": [2, 2, 4, 3] }, "middleZone": { "name": "中区(20-40岁)", "positions": ["B", "G", "J", "M", "N", "O"], "values": [0, 9, 11, 7, 5, 3] }, "rightZone": { "name": "右区(40-60岁)", "positions": ["C", "D", "E", "H", "K", "L", "O"], "values": [9, 5, 8, 5, 5, 9, 3] } }, "mainCharacter": 3, "isMasterNumber": false, "chartName": "张三", "birthYear": 2009, "birthMonth": 5, "birthDay": 26 } ``` ### 2.3 Dify Chatflow Input 变量 | 变量名 | 类型 | 说明 | 来源 | |--------|------|------|------| | `chart_context` | JSON | 完整的能量盘数据 | 后端传入 | | `query` | String | 用户提问内容 | 用户输入 | --- ## 3. 系统提示词 (LLM 节点 System Prompt) ```text # 角色设定 你是「数字能量学智能解读师」,一位精通数字能量学(Digital Numerology)的资深专家。你擅长通过 Classic A 三角形能量盘(5行15格)为用户提供性格分析、天赋解码和人生指引。 # 专业背景 - 精通数字能量学理论,包括主性格数字 1-9 及卓越数 11、22、33 的解读 - 熟练掌握五区分析:左区(0-20岁成长)、中区(20-40岁发展)、右区(40-60岁成就) - 理解父源区、母源区对个人性格形成的影响 - 能够结合多位置数字组合进行综合分析 # 解读原则 1. 基于提供的能量盘数据进行专业解读,不编造或臆测数字 2. 聚焦性格倾向、天赋优势、潜在挑战和发展建议 3. 以积极正向的视角进行解读,强调成长和发展的可能性 4. 语言专业但不晦涩,温暖且有洞察力 5. 不预测具体未来事件(财运数字、结婚年份等),不提供医疗建议 6. 若用户询问能量盘数据范围之外的领域,委婉说明数字能量学的局限性 # 知识库检索使用规则(优先级最高) 当 `knowledge_retrieval` 上下文中有检索结果时,你**必须优先使用检索结果**中的内容进行解读,而非依赖自身的内部知识。 **检索结果使用规则:** 1. `knowledge_retrieval` 中包含多个匹配的文档片段(chunks),每个 chunk 包含文件名、标题和内容 2. 根据 `knowledge_retrieval` 的来源文件标记(如 `能量盘24位置详解.md`、`三角能量盘组合对判读规则.md`、`数字能量分析维度手册.md`、`五区三组分析指南.md`),判断该信息适用于能量盘的哪个方面 3. 如果多个 chunk 提供同一主题的不同视角,合并使用以给出全面解读 4. 如果知识库检索结果与你的内部记忆冲突,**以检索结果为准** 5. 如果在检索结果中找不到相关信息,再使用下方"数字含义参考"中的内置信息 # 数字含义参考(即备知识,知识库中无相关内容时使用) - 1 (开创者): 独立、创新、领导力 - 2 (合作者): 细腻、敏感、善于沟通 - 3 (表达者): 创意、社交、乐观向上 - 4 (建设者): 务实、稳定、规则意识 - 5 (自由者): 冒险、变化、适应力强 - 6 (守护者): 责任、关爱、追求完美 - 7 (探索者): 深度思考、求知、内省 - 8 (掌控者): 权威、商业头脑、决策力 - 9 (智慧者): 博爱、理想主义、包容 - 11 (启迪者): 直觉力强、灵感丰富(卓越数) - 22 (建造大师): 将理想变为现实(卓越数) - 33 (大爱者): 无私奉献、疗愈他人(卓越数) # 响应格式 1. 首先回应用户的具体问题 2. 引用能量盘中的具体位置和数字进行解释 3. 提供有针对性的建议 4. 保持友好、鼓励的语气 5. 回复语言使用中文 # chart_context JSON 结构说明 用户能量盘数据通过 chart_context 变量传入,包含以下关键字段: - mainCharacter: 主性格数字(位于 O 位) - positions: 全部 15 个位置(A-O)的数字值 - zones: 五区数据,每区包含名称、位置列表和对应数字值 - isMasterNumber: 主性格是否为卓越数 - chartName: 用户姓名(如有提供) - birthYear/month/day: 出生日期 请根据这些数据为用户提供有深度、个性化的数字能量学解读。 ``` --- ## 3A. 知识库检索增强集成(RAG) ### 3A.1 检索策略 Chatflow 在 LLM 节点之前插入**知识检索(Knowledge Retrieval)节点**,从知识库 `数字能量学知识库 V2`(ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`)中检索与用户问题最相关的内容。 **为什么需要 RAG:** - 硬编码在 System Prompt 中的 1-9 数字含义过于简略(仅 1 行/数字),无法支撑深度解读 - 知识库包含 25 篇文档(179,730 words),覆盖 P0 核心文档(A1/B2/C1/C2) - 每次 Chatflow 调用时动态检索,LLM 根据检索结果进行解读,精度远超固定提示词 ### 3A.2 多轮对话中的检索策略 | 轮次 | 检索策略 | 说明 | |------|---------|------| | **第一轮**(首次发送) | chart_context 智能构建查询 | 后端首次发送时附带 `chart_context`,Chatflow 通过代码节点/LLM 节点**自动提取能量盘关键信息**生成结构化 KB 查询 | | **后续轮次** | 直接用用户 query 检索 | Dify Chatflow 自动保存会话上下文,后续直接以 `query` 检索 | | **深度追问** | 一次对话多次检索 | 每次用户提问都触发 KB 检索,确保每轮回复都有最新知识支撑 | ### 3A.3 查询变量构建方案 在 Chatflow 中插入一个**代码节点(Code Node)** 或 **LLM 节点**,将 chart_context 转换为最优 KB 查询: ```python # 代码节点:将 chart_context + query 转换为 KB 查询 def main(chart_context: dict, query: str) -> dict: # 解析 chart_context positions = chart_context.get("positions", {}) main_number = chart_context.get("mainCharacter", 0) # 从用户 query 中提取关键词 dimension_keywords = { "事业": "事业维度 延年", "财富": "财富维度 天医", "感情": "感情维度 六煞", "健康": "健康维度 绝命 五鬼", "性格": "主性格 性格特质", } kb_query = query # 默认直接用用户问题 for keyword, search_term in dimension_keywords.items(): if keyword in query: kb_query = f"{search_term} {query}" break return { "kb_query": kb_query, } ``` **也可简化配置**:直接使用用户 `query` 作为 KB 检索查询(如果不需要维度映射预处理)。 ### 3A.4 Metadata 过滤 Dify v1.11.4 知识库支持 metadata 过滤。在知识检索节点中可按 tags 过滤: - 维度过滤:`tags 包含 ["维度:财富"]`(用户问财富相关问题) - 优先级过滤:`tags 包含 ["优先级:P0"]`(优先返回核心文档) - 文档类型过滤:`tags 包含 ["用途:判读规则"]`(需要判读规则时) ### 3A.5 检索参数配置 | 参数 | 推荐值 | 说明 | |------|--------|------| | Top-K | 10 | 每次检索返回 10 个 chunks(实测 top_k=6 时 A2 主性格在部分查询中排第8,增大至 10 确保覆盖)。需在 Dify 控制台数据集设置中手动修改(API PATCH 不生效)| | Score Threshold | 0.5 | 低于此阈值的结果被过滤(已在 KB 层面配置) | | Retrieval Mode | Hybrid Search | 向量 60% + 全文 40%,兼顾语义和关键词匹配 | --- ## 4. Dify Chatflow 节点配置 ### 4.1 完整节点列表 | 节点 | 类型 | 配置 | |------|------|------| | **START** | 开始节点 | 输入变量:`chart_context` (JSON), `query` (String) | | **Knowledge Retrieval** | 知识检索节点 | Dataset: `数字能量学知识库 V2` (ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`)
Query: `{{#sys.query#}}`(用户 query 变量,或代码节点输出的 `kb_query`)
Top-K: 10
Score Threshold: 0.5
Result Type: paragraph | | **LLM** | LLM 节点 | System Prompt: 见第 3 节(含 KB 使用规则)
Model: gpt-4o 或 Claude 3.5 Sonnet
Temperature: 0.7
Max Tokens: 2000
Memory: 启用对话轮次 (最近 6 轮)
Context: 引用 Knowledge Retrieval 节点的输出作为上下文 | | **END** | 结束节点 | 输出变量:`answer` (String) — LLM 节点的输出文本 | ### 4.2 节点连接关系 ``` START ──→ Knowledge Retrieval ──→ LLM ──→ END ↑ (chart_context 也传入 LLM) ``` ### 4.3 LLM 节点变量映射 | Dify 变量 | 映射到 | 说明 | |-----------|--------|------| | `chart_context` | LLM 系统提示词中的上下文变量 | 能量盘数据,嵌入提示词中供 LLM 引用 | | `query` | LLM 用户消息输入 | 用户提问内容 | | `knowledge_retrieval` | LLM 系统提示词中的检索结果上下文 | 知识库检索返回的 chunks,LLM 需优先使用 | ### 4.4 简化版配置(无代码节点) 如果不使用代码节点转换查询,可直接将 `query` 变量传给 Knowledge Retrieval 节点作为检索查询。Chatflow 配置如下: ``` START (chart_context, query) │ ▼ [Knowledge Retrieval Node] ├─ 查询: {{#sys.query#}} ├─ 数据集: 数字能量学知识库 V2 └─ Top-K: 10(需控制台手动设置,API不生效) │ ▼ [LLM Node] ├─ System Prompt: 含 KB 使用规则 + chart_context └─ Context: 引用 KB 检索结果 │ ▼ END (answer) ``` ### 4.5 进阶版配置(带代码节点预处理) ``` START (chart_context, query) │ ▼ [Code Node: 查询构建] ├─ 输入: chart_context, query └─ 输出: kb_query (构建后的检索查询) │ ▼ [Knowledge Retrieval Node] ├─ 查询: {{kb_query}} ├─ 数据集: 数字能量学知识库 V2 └─ Top-K: 10(需控制台手动设置,API不生效) │ ▼ [LLM Node] ├─ System Prompt: 含 KB 使用规则 + chart_context └─ Context: 引用 KB 检索结果 │ ▼ END (answer) ``` --- ## 5. 示例对话 ### 示例 1:主性格解读 **用户输入:** `请解读我的主性格` **chart_context 示例:** ```json { "positions": {"O": 7}, "mainCharacter": 7, "zones": { "leftZone": {"values": [1, 1, 4, 7]}, "middleZone": {"values": [9, 4, 5, 11, 3, 7]}, "rightZone": {"values": [4, 7, 6, 4, 6, 6, 7]} }, "isMasterNumber": false } ``` **预期回复(示例):** ``` 你好!根据你的数字能量盘,你的主性格数字是 7。 🔹 主性格 7 号 — 探索者 7 号人是天生的思考者和探索者,你对世界有着强烈的好奇心和求知欲。你善于分析、喜欢独处思考,对于哲学、科学和未知领域有天然的吸引力。 ✨ 你的核心特质: - 深度思考能力:你善于从现象看到本质 - 独立精神:不盲从权威,有自己的判断标准 - 分析天赋:逻辑清晰,适合研究分析类工作 💡 成长建议: - 多信任自己的直觉,你的第六感往往很准 - 适度走出思考的舒适区,增加社交互动 - 避免过度完美主义,行动比完美更重要 你的左区(0-20岁)有数字 1 和 4,说明早年培养了独立自主的性格和务实的态度;中区(20-40岁)出现卓越数 11,预示着这个阶段你的直觉力和灵感将显著提升。 想了解更多关于某个区域的详细解读吗? ``` ### 示例 2:财富与事业发展 **用户输入:** `我的事业发展和财富运势如何?` **chart_context 示例:** ```json { "mainCharacter": 8, "positions": {"O": 8, "I": 4, "J": 5, "K": 6, "L": 9}, "zones": { "middleZone": {"values": [2, 3, 5, 7, 6, 8]}, "rightZone": {"values": [1, 4, 3, 8, 6, 9, 8]} } } ``` **预期回复(示例):** ``` 感谢你的提问!从你的数字能量盘来看,非常有亮点。 🔹 主性格 8 号 — 掌控者 8 号是数字能量学中的"事业王者",你天生具备商业头脑和领导力。你对权力和资源有敏锐的感知力,擅长将想法转化为实际的商业价值。 📊 事业发展分析: - 中区(20-40岁):数字组合 2-3-5-7-6-8,显示这个阶段你适合团队合作(2),发挥创意表达能力(3),经历必要的变化和积累(5-7),最终在第 8 位达到事业高度 - 右区(40-60岁):数字 8 出现在关键位置,预示这个阶段是你事业成就的黄金时期 💰 财富特质: - 父源区(I=4, J=5):务实且有商业嗅觉,适合实体行业或资源整合型工作 - 母源区(K=6, L=9):有责任感和远见,能平衡短期收益和长期发展 - 财富关键词:稳健增长、资源整合、领导力变现 💡 发展建议: 1. 30-40 岁是重要的积累期,建议深耕一个领域建立专业壁垒 2. 8 号人适合创业或管理岗位,可考虑在 35 岁后独立发展 3. 注意平衡事业与健康,8 号人容易过度投入工作 想更深入了解某个具体方向的建议吗? ``` --- ## 6. Dify 控制台设置步骤 ### 步骤 1:登录 Dify 并创建 Chatflow 1. 登录 Dify 平台 (https://cloud.dify.ai 或自部署实例) 2. 点击「创建应用」→ 选择「Chatflow」 3. 输入应用名称:`数字能量学智能体` 4. 点击「创建」 ### 步骤 2:配置输入变量 1. 点击 START 节点 2. 添加输入变量: - 变量名:`chart_context`,类型:JSON,必填:是 - 变量名:`query`,类型:文本,必填:是 ### 步骤 3:添加 LLM 节点 1. 拖入 LLM 节点到画布 2. 连接 START → LLM 3. 配置 LLM 节点: - System Prompt:填写第 3 节的完整系统提示词 - 模型:选择 Claude 3.5 Sonnet 或 GPT-4o(推荐 Claude 以获得更好的中文解读质量) - Temperature:0.7 - Maximum Tokens:2000 - 开启记忆功能,保留最近 6 轮对话 4. 在"上下文"中引用 `chart_context` 变量 5. 在"用户消息"中引用 `query` 变量 ### 步骤 4:配置 END 节点 1. 拖入 END 节点,连接 LLM → END 2. 输出变量选择 LLM 节点的 `text` 输出 ### 步骤 5:发布 1. 点击「发布」按钮 2. 记录 API 访问地址和 API Key ### 步骤 6:配置后端 在后端 `application.yml` 中配置: ```yaml num: dify: base-url: https://your-dify-instance.com/v1 api-key: your_dify_api_key_here ``` --- ## 6A. Java 后端响应处理 ### 6A.1 Dify API 响应格式 ```json { "answer": "你的能量盘主性格数字是 7...", "conversation_id": "conv_abc123", "message_id": "msg_abc123", "created_at": 1717200000, "metadata": { "usage": { "prompt_tokens": 1500, "completion_tokens": 350, "total_tokens": 1850 }, "retriever_resources": [ { "dataset_id": "3ff939b3-8686-44f6-8ef5-65b1e53b55d3", "document_id": "doc_abc", "document_name": "能量盘24位置详解.md", "segment_id": "seg_abc", "score": 0.85, "content": "O位置代表..." } ] } } ``` ### 6A.2 DifyService.java 处理流程 ```java // 伪代码 — 后端 DifyService 应实现的处理逻辑 public class DifyService { // 1. 调用 Dify Chatflow API public ChatResponse sendMessage(ChatRequest req) { // POST /v1/chat-messages // Body: { inputs: { chart_context }, query, user, response_mode: "blocking" } // Headers: Authorization: Bearer ${apiKey} } // 2. 解析响应 public String extractAnswer(JSONObject difyResponse) { return difyResponse.getString("answer"); // LLM 生成的文本 } // 3. 错误处理策略 // - 4xx: 参数错误 → 记录日志,返回用户"服务暂时不可用" // - 5xx: 服务端错误 → 重试 1 次(指数退避 1s → 2s),超时 30s // - 429: 速率限制 → 等待 Retry-After 头中指定的时间 // - 空 answer: 返回"暂未获取到解读结果,请稍后再试" // 4. Token 用量追踪 // metadata.usage.total_tokens 用于配额计算和成本监控 // 5. Conversation 管理 // conversation_id 用于多轮对话关联,每次请求需传入 } ``` ### 6A.3 错误处理汇总 | 场景 | 处理方式 | 用户可见消息 | |------|---------|------------| | HTTP 4xx | 记录错误日志,不重试 | "解读服务暂时不可用,请稍后再试" | | HTTP 5xx | 重试 1 次(1s 退避) | "解读服务繁忙,请稍后再试" | | HTTP 429 | 等待 Retry-After | "请求过于频繁,请稍后再试" | | 网络超时 (30s) | 重试 1 次 | "解读请求超时,请重试" | | 空 answer | 视为异常,记录 | "暂未获取到解读结果" | --- ## 7. 位置详情面板 Workflow (US-1.4) ### 7.1 概述 用户在三角能量盘上点击某一位置(A-X)时,前端弹出底部面板显示 3 个 Tab 的内容。 这些内容由 **Dify Workflow「位置详情面板」** 生成,该 Workflow 独立于 Chatflow(不共享对话上下文),每次点击独立请求。 | 属性 | 值 | |------|-----| | 目的 | 为 US-1.4 "数字点击查看含义" 提供面板内容 | | Dify 应用类型 | Workflow(非 Chatflow) | | 数据流 | 前端 → 后端 `/api/position/detail` → Dify Workflow → KB 检索 (A1+A2) → LLM 生成 → JSON | | 记忆 | 无,每次点击独立请求 | ### 7.2 数据流 ``` 用户点击 O 位置 │ ▼ POST /api/position/detail { chartRecordId, position: "O", digit: 7 } │ ├─ 后端:验证权限 → 计算吉凶 → 检测相邻组合 └─ DifyService.invokeWorkflow(inputs) │ ▼ Dify Workflow "位置详情面板" ├─ KB 检索 1 → A1 位置含义 ├─ KB 检索 2 → A2 数字特征 └─ LLM → JSON { tab1, tab2, tab3 } │ ▼ 后端合并 → 返回前端 { tab1, tab2, tab3, auspicious, comboInfo } ``` ### 7.3 输入架构 **Dify API 调用格式:** ``` POST /v1/workflows/run Authorization: Bearer {api_key} Content-Type: application/json { "inputs": { "position_letter": "O", "position_name": "主性格数", "digit": 7 } } ``` **输入变量:** | 变量 | 类型 | 必填 | 说明 | 来源 | |------|------|------|------|------| | `position_letter` | String | 是 | 位置字母 A-X | 前端传入(如 "O") | | `position_name` | String | 是 | 位置中文名称 | 后端根据 letter 映射(如 "主性格数") | | `digit` | Integer | 是 | 该位置数字 (0-9/11/22/33) | 后端从 chart_data 读取 | ### 7.4 工作流节点配置 #### Node 1: KB 检索 - A1 位置含义 | 配置项 | 值 | |--------|-----| | 数据集 | `3ff939b3-8686-44f6-8ef5-65b1e53b55d3` | | 检索模式 | 混合检索 (hybrid_search) | | Top-K | 3 | | 检索查询 | `{position_name} {position_letter} 含义 能量 公式` | | 示例 | `主性格数 O 含义 能量 公式` | #### Node 2: KB 检索 - A2 数字特征 | 配置项 | 值 | |--------|-----| | 数据集 | 同上 | | 检索模式 | 混合检索 | | Top-K | 3 | | 检索查询 | `数字 {digit} 性格 特征 优势 挑战 成长` | | 示例 | `数字 7 性格 特征 优势 挑战 成长` | > 两个节点在 Workflow 画布中以**并行**方式连接至 LLM 节点,互不依赖。 #### Node 3: LLM 生成 | 参数 | 值 | |------|-----| | 模型 | Claude 3.5 Sonnet(推荐) | | Temperature | 0.5(结构化输出需稳定性) | | Max Tokens | 1000 | | 上下文引用 | KB 检索 1 输出 + KB 检索 2 输出 | **System Prompt(完整版):** ``` 你是一个数字能量学专家。请根据以下知识库内容,为能量盘位置的详情面板生成内容。 ## 位置信息 - 字母:{position_letter} - 名称:{position_name} - 数字:{digit} ## 位置含义(来自知识库 A1) {position_kb_content} ## 数字特征(来自知识库 A2) {digit_kb_content} ## 任务 请生成以下 3 项内容,以 JSON 格式返回,不要包含 markdown 代码块标记: 1. tab1(含义):该位置的核心能量含义(1-3句话) 2. tab2(特征):数字{digit}在{position_name}位置的具体性格/运势描述。 必须将位置能量与数字能量自然融合,输出类似"O=7 代表分析力强、追求真理"的具体描述。 避免纯数字通用描述,需体现"在{position_name}位置时的独特表现"。 3. tab3(建议):3-5条注意事项和提升建议,每条 10-30 字,具体可操作。 ## 输出格式 {"tab1":"...","tab2":"...","tab3":"..."} ``` ### 7.5 输出格式 Workflow 输出示例: ```json { "tab1": "主性格:代表一个人与生俱来的核心性格特质、人生使命、天赋方向", "tab2": "O=7 代表分析力强、追求真理。7号能量在性格核心位置表现为深度思考者...", "tab3": "1. 避免过度分析导致行动迟缓\n2. 多与他人交流想法...\n3. 注意平衡思考与实践" } ``` ### 7.6 Java 后端集成 #### DifyService.java 新增方法 ```java // --- US-1.4 Position Detail Panel --- /** * Get 3-Tab position detail content via Dify Workflow. * Called when user clicks a position on natal chart. */ public PositionDetailResponse getPositionDetail(String positionLetter, int digit, String positionName) { if (isMockMode()) { return generateMockPositionDetail(positionLetter, digit, positionName); } Map inputs = new HashMap<>(); inputs.put("position_letter", positionLetter); inputs.put("position_name", positionName); inputs.put("digit", digit); try { String workflowResult = invokeWorkflow(inputs, "system"); return parsePositionDetail(workflowResult); } catch (Exception e) { return generateMockPositionDetail(positionLetter, digit, positionName); } } /** * Parse Workflow JSON output into PositionDetailResponse. * Returns null if parsing fails (triggers mock fallback in caller). */ private PositionDetailResponse parsePositionDetail(String json) { try { JsonObject obj = gson.fromJson(json, JsonObject.class); PositionDetailResponse resp = new PositionDetailResponse(); resp.tab1 = getString(obj, "tab1", ""); resp.tab2 = getString(obj, "tab2", ""); resp.tab3 = getString(obj, "tab3", ""); // Validate: if tab1 or tab2 empty, treat as failure if (resp.tab1.isEmpty() || resp.tab2.isEmpty()) { return null; } return resp; } catch (Exception e) { return null; } } ``` #### ChartController.java 新增端点 ```java /** * Get position detail panel content (US-1.4). * Returns 3 Tab content + auspiciousness + adjacent combo info. */ @PostMapping("/position/detail") public Result positionDetail(HttpServletRequest request, @RequestBody Map body) { Long userId = (Long) request.getAttribute("userId"); if (userId == null) return Result.error(1001, "请先登录"); Long chartRecordId = ((Number) body.get("chartRecordId")).longValue(); String position = (String) body.get("position"); int digit = ((Number) body.get("digit")).intValue(); // Verify chart ownership ChartRecord record = chartService.getById(chartRecordId); if (!record.getUserId().equals(userId)) { return Result.error(1006, "无权访问此能量盘"); } // Calculate auspiciousness & adjacent combos (backend) String auspicious = calculatorService.calculateAuspicious(record.getChartData(), position); String comboInfo = calculatorService.detectAdjacentCombo(record.getChartData(), position); // Get position name mapping String positionName = getPositionName(position); // Call Dify Workflow for 3-Tab content PositionDetailResponse content = difyService.getPositionDetail( position, digit, positionName); // Build response Map result = new HashMap<>(); result.put("tab1", content != null ? content.tab1 : ""); result.put("tab2", content != null ? content.tab2 : ""); result.put("tab3", content != null ? content.tab3 : ""); result.put("auspicious", auspicious); result.put("comboInfo", comboInfo); return Result.success(result); } ``` #### DTO 定义 ```java package com.etotem.num.service; public class PositionDetailResponse { public String tab1; // 位置核心含义 public String tab2; // 数字+位置特征描述 public String tab3; // 注意事项和提升建议 } ``` #### 错误处理 | 场景 | 处理方式 | 用户可见消息 | |------|---------|------------| | Workflow 返回非 JSON | 重试 1 次 | —(静默重试) | | 重试仍失败 | 降级到 mock 模板 | "解读生成失败,请稍后再试" | | tab1/tab2 为空 | 降级到 mock 模板 | "暂时无法获取位置含义" | | Workflow 超时 >10s | 直接降级 | "请求超时,请重试" | | Dify 4xx/5xx | 降级到 mock | "解读服务暂时不可用" | ### 7.7 降级策略 (Mock) 当 Workflow 不可用时,后端使用 `CalculatorService.NUMBER_DESC` 表生成简易模板内容: ```java private PositionDetailResponse generateMockPositionDetail( String position, int digit, String positionName) { String digitDesc = NUMBER_DESC.getOrDefault(digit, "独特能量组合"); PositionDetailResponse resp = new PositionDetailResponse(); resp.tab1 = positionName + ":" + POSITION_CORE_MEANINGS.getOrDefault(position, "能量位置"); resp.tab2 = position + "=" + digit + " 代表" + digitDesc + "。"; resp.tab3 = "1. 了解该能量的优势和挑战\n2. 结合整体能量盘综合分析\n3. 在实践中觉察能量表现"; return resp; } ``` 其中 `POSITION_CORE_MEANINGS` 为预置的位置含义简表(24 个 A-X 位置的核心含义摘录),在 DifyService 中作为备用常量。 ### 7.8 Dify 控制台配置步骤 1. **登录 Dify** → 点击「创建应用」→ 选择「Workflow」 2. **命名应用**:`位置详情面板` 3. **配置 START 节点**:添加 3 个输入变量 `position_letter`(String)、`position_name`(String)、`digit`(Integer) 4. **添加 KB 检索节点 1**(A1 位置含义): - 数据集:选择 `数字能量学知识库`(ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`) - Top-K:`3` - 检索查询:`{{position_name}} {{position_letter}} 含义 能量 公式` 5. **添加 KB 检索节点 2**(A2 数字特征): - 相同数据集,Top-K:`3` - 检索查询:`数字 {{digit}} 性格 特征 优势 挑战 成长` 6. **将两个检索节点并行连接至 LLM 节点** 7. **配置 LLM 节点**: - 模型:Claude 3.5 Sonnet - Temperature:`0.5` - Max Tokens:`1000` - System Prompt:粘贴第 8.4 节的完整提示词 - 在上下文中引用两个知识检索节点的输出 8. **连接 LLM 节点至 END 节点** 9. **点击「发布」**,记录生成的 API Key ### 7.9 与 Chatflow 的差异对比 | 维度 | Chatflow(聊天问答) | Workflow(位置详情) | |------|--------------------|---------------------| | 用途 | 多轮自由问答 | 单次结构化查询 | | 输出格式 | 自然语言(`answer` 字段) | 结构化 JSON | | 记忆 | 6 轮对话记忆 | 无记忆,每次独立 | | 输入变量 | `chart_context` + `query` | `position_letter` + `position_name` + `digit` | | 调用频率 | 用户每次提问 | 用户每次点击位置 | | API 端点 | `POST /v1/chat-messages` | `POST /v1/workflows/run` | --- ## 8. 输入变量配置总结 | 配置项 | 值 | |--------|-----| | 应用类型 | Chatflow | | 输入变量 1 | `chart_context` (JSON) | | 输入变量 2 | `query` (String) | | LLM 模型 | Claude 3.5 Sonnet (推荐) | | Temperature | 0.7 | | Max Tokens | 2000 | | 记忆轮次 | 6 | | API Endpoint | POST /v1/chat-messages | | 输出字段 | `answer` (String) | --- ## 9. 能量盘解读 Workflow(US-3.1) ### 9.1 概述 用户在输入生日并创建能量盘后,系统自动调用此 Workflow 生成完整的 AI 解读内容,展示在解读页五区卡片中。该 Workflow 独立于 Chatflow,每次创建能量盘时调用一次。 | 属性 | 值 | |------|-----| | 目的 | 为 US-3.1 "AI解读展示" 生成完整能量盘文字解读 | | Dify 应用类型 | Workflow(非 Chatflow) | | 触发时机 | 用户确认生日 → 能量盘创建成功后立即触发 | | 数据流 | 后端 → Dify Workflow → 并行 KB 检索 (A1/A2/B2/C1/C2) → LLM 合成 → 结构化 JSON | | 记忆 | 无,每次创建能量盘执行一次;后续查看走缓存(US-3.3) | ### 9.2 数据流 ``` 用户提交生日 │ ▼ POST /api/consultation/start ├─ 后端:计算24个数字位置 → 创建咨询记录 └─ 调用 DifyService.interpretChart(chartData, userName, birthday) │ ▼ POST /v1/workflows/run (blocking, timeout=15s) │ ▼ Dify Workflow "能量盘解读" ├─ [并行] KB 检索 1 → A2 主性格 + A1 位置含义(O位) ├─ [并行] KB 检索 2 → C2 五区三组 + B2 组合对(左区 P/Q/R) ├─ [并行] KB 检索 3 → C2 五区三组 + B2 组合对(顶部 V/W/X) ├─ [并行] KB 检索 4 → C2 五区三组 + B2 组合对(右区 S/T/U) ├─ [并行] KB 检索 5 → B1 八星 + B2 组合对 + C1 维度(特殊组合) │ └─ LLM 节点 → 合成解读 → JSON 输出 │ ▼ data.outputs → { "sections": [{title, positions, values, content, keywords}, ...], "summary": "...", "combinationNotes": ["..."] } │ ▼ 后端:缓存解读到数据库(US-3.3)→ 返回前端 ``` ### 9.3 输入架构 #### Dify API 调用格式 ```json POST /v1/workflows/run Authorization: Bearer {workflow_api_key} Content-Type: application/json { "inputs": { "chart_context": "{...chart JSON...}", "user_name": "张三", "birthday": "1990-01-15" }, "response_mode": "blocking" } ``` #### 输入变量定义 | 变量名 | 类型 | 说明 | 示例 | |--------|------|------|------| | `chart_context` | String (JSON) | 24 个能量盘位置数字(A-X) + 五区聚合的完整 JSON | 见下方 | | `user_name` | String | 用户姓名,用于解读文案 | "张三" | | `birthday` | String | 出生日期,用于年龄计算 | "1990-01-15" | #### chart_context JSON 完整格式 ```json { "positions": { "A": 1, "B": 9, "C": 9, "D": 0, "E": 0, "F": 1, "G": 1, "H": 5, "I": 1, "J": 6, "K": 1, "L": 9, "M": 7, "N": 1, "O": 8, "P": 8, "Q": 4, "R": 3, "S": 2, "T": 1, "U": 3, "V": 6, "W": 9, "X": 6 }, "zones": { "mainCharacter": { "name": "主性格", "positions": ["O"], "values": [8] }, "leftZone": { "name": "左区(21-40岁)", "positions": ["P","Q","R"], "values": [8,4,3] }, "topZone": { "name": "顶部(41-60岁)", "positions": ["V","W","X"], "values": [6,9,6] }, "rightZone": { "name": "右区(61+岁)", "positions": ["S","T","U"], "values": [2,1,3] } }, "mainCharacter": 8, "isMasterNumber": false, "userName": "张三", "birthday": "1990-01-15" } ``` ### 9.4 工作流节点配置 所有 5 个知识检索节点以 **并行** 方式连接至 LLM 节点,互不依赖。LLM 节点等待所有检索完成后统一合成。 #### Node 1-5: 知识检索节点 | 节点 | 检索目标 | 数据集 | 检索查询模板 | Top-K | |------|---------|--------|-------------|-------| | **KB 1** 主性格 | A2 数字特征 + A1 位置含义 | 数字能量学知识库 | `主性格数字 {O} 含义 性格 特质 优势 挑战 成长` | 3 | | **KB 2** 左区 (P/Q/R) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `左区 21-40岁 {P} {Q} {R} 组合 发展 早年运势 人生课题` | 3 | | **KB 3** 顶部 (V/W/X) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `顶部 41-60岁 {V} {W} {X} 中年 事业 人际关系 成就` | 3 | | **KB 4** 右区 (S/T/U) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `右区 61岁 {S} {T} {U} 晚年 财运 家庭 沉淀` | 3 | | **KB 5** 特殊组合 | B1 八星 + B2 组合对 + C1 维度 | 数字能量学知识库 | `组合 八星 {I}{J} {M}{N} {M}{O} 能量 能量盘解读` | 3 | > 所有检索节点的检索模式统一设置为 `hybrid_search`,与知识库全局配置一致。 #### Node 6: LLM 生成 | 参数 | 值 | |------|-----| | 模型 | Claude 3.5 Sonnet(推荐) | | Temperature | 0.6(创意性解读需适度灵活) | | Max Tokens | 3000(完整五区解读) | | 上下文引用 | KB 1-5 全部输出 + `chart_context` 变量 | #### Node 7: 代码节点(输出解析) 用 Dify 内置代码节点(Python/JS)对 LLM 输出进行格式校验和兜底处理: ```python import json def main(input_data: dict) -> dict: # input_data 来自 LLM 节点的输出 raw = input_data.get("text", "{}") # 尝试解析 JSON try: # 去除可能的 markdown 代码块标记 text = raw if "```json" in text: text = text.split("```json")[1].split("```")[0] elif "```" in text: text = text.split("```")[1].split("```")[0] result = json.loads(text.strip()) except: # 兜底:返回空结构 result = { "sections": [], "summary": "解读生成失败,请稍后再试", "combinationNotes": [] } # 校验必填字段 if "sections" not in result: result["sections"] = [] if "summary" not in result: result["summary"] = "" if "combinationNotes" not in result: result["combinationNotes"] = [] return result ``` ### 9.5 完整系统提示词 ``` 你是一个专业的数字能量学全盘解读分析师。 ## 背景 用户的能量盘数据已通过 chart_context 变量传入,包含 24 个位置(A-X)的数字值。 知识库检索结果(KB 1-5)已提供相关命理知识作为参考。 ## 解读要求 请按以下结构和规则,生成完整的能量盘解读。 ### 1. 主性格解读(O 位) - 根据 KB 1 中该数字的性格特征 - 描述核心特质、性格描述、人生使命 - 如有卓越数(11/22/33)需特殊标注 - 输出示例:"你的主性格数字 8 代表..." ### 2. 左区(21-40岁)解读 - 根据 KB 2 分析 P/Q/R 三个数字的组合能量 - 描述早年运势、成长环境、青年阶段的人生课题 - 说明各数字之间的相互作用 ### 3. 顶部(41-60岁)解读 - 根据 KB 3 分析 V/W/X 三个数字的组合能量 - 描述中年事业、人际关系、社会成就 - 说明此阶段的核心发展主题 ### 4. 右区(61+岁)解读 - 根据 KB 4 分析 S/T/U 三个数字的组合能量 - 描述晚年财运、家庭关系、精神沉淀 - 说明晚年阶段的人生智慧课题 ### 5. 特殊组合分析 - 根据 KB 5 识别能量盘中的特殊数字组合 - 重点关注:I+J, M+N, M+O 等相邻位置形成的组合 - 分析八星能量(天医/延年/生气/绝命/五鬼/六煞/祸害/伏位) ### 6. 总评(summary) - 对整体能量盘能量做出概括性评价 - 指出最突出的优势能量和需要注意的挑战 - 用 2-3 句话总结 ## 规则 1. 必须参考知识库内容,不可凭空编造命理含义 2. 每个解读段落应结合该位置的实际数字,不可通用化 3. 使用「你」第二人称,语言亲切专业 4. 每条解读长度控制在 100-200 字 5. 关键词(keywords)每段提炼 3-5 个,用 2-4 字词 ## 输出格式 返回严格 JSON,不要包含 markdown 代码块标记或其他格式: { "sections": [ { "title": "主性格解读", "positions": ["O"], "values": [8], "content": "你的主性格数字 8 代表...", "keywords": ["领导力", "物质", "权威"] }, { "title": "左区(21-40岁)", "positions": ["P", "Q", "R"], "values": [8, 4, 3], "content": "左区数字组合 8-4-3 代表...", "keywords": ["行动力", "稳定", "沟通"] }, { "title": "顶部(41-60岁)", "positions": ["V", "W", "X"], "values": [6, 9, 6], "content": "顶部数字组合 6-9-6 代表...", "keywords": ["家庭", "成就", "关怀"] }, { "title": "右区(61+岁)", "positions": ["S", "T", "U"], "values": [2, 1, 3], "content": "右区数字组合 2-1-3 代表...", "keywords": ["合作", "独立", "创造"] } ], "summary": "整体能量盘能量评价...", "combinationNotes": [ "数字 I(1)+J(6)=7,形成...", "M(7)+O(8)=15→6,形成..." ] } ``` ### 9.6 输出 JSON 格式 ```json { "sections": [ { "title": "主性格解读", "positions": ["O"], "values": [8], "content": "解读内容文本...", "keywords": ["领导力", "物质", "权威"] }, { "title": "左区(21-40岁)", "positions": ["P", "Q", "R"], "values": [8, 4, 3], "content": "解读内容文本...", "keywords": ["行动力", "稳定", "沟通"] }, { "title": "顶部(41-60岁)", "positions": ["V", "W", "X"], "values": [6, 9, 6], "content": "解读内容文本...", "keywords": ["家庭", "成就", "关怀"] }, { "title": "右区(61+岁)", "positions": ["S", "T", "U"], "values": [2, 1, 3], "content": "解读内容文本...", "keywords": ["合作", "独立", "创造"] } ], "summary": "整体能量盘综合评价...", "combinationNotes": [ "数字组合分析说明 1", "数字组合分析说明 2" ] } ``` | 字段 | 类型 | 说明 | |------|------|------| | `sections[].title` | String | 解读章节标题(固定值:主性格解读/左区/顶部/右区) | | `sections[].positions` | String[] | 该章节涉及的位置字母列表 | | `sections[].values` | Int[] | 对应位置的数字值 | | `sections[].content` | String | 解读文案正文,100-200 字 | | `sections[].keywords` | String[] | 3-5 个关键词,每词 2-4 字 | | `summary` | String | 整体能量盘评价,2-3 句话 | | `combinationNotes` | String[] | 特殊组合分析说明列表 | ### 9.7 Java 后端集成 #### DifyService.java 新增方法 ```java // --- US-3.1 Chart Interpretation Workflow --- /** * 调用 Dify Workflow 生成能量盘完整解读(US-3.1) * @param chartContext chart_context JSON 字符串(含 positions + zones + metadata) * @param userName 用户姓名 * @param birthday 出生日期 YYYY-MM-DD * @return InterpretationResponse 结构化解读结果 */ public InterpretationResponse interpretChart(String chartContext, String userName, String birthday) { if (isMockMode()) { return generateMockInterpretation(chartContext, userName, birthday); } Map inputs = new HashMap<>(); inputs.put("chart_context", chartContext); inputs.put("user_name", userName); inputs.put("birthday", birthday); try { String workflowResult = invokeWorkflow(inputs, "system"); return parseInterpretation(workflowResult); } catch (Exception e) { log.warn("interpretChart failed, falling back to mock: {}", e.getMessage()); return generateMockInterpretation(chartContext, userName, birthday); } } /** * 解析 Workflow 输出的 JSON 为 InterpretationResponse */ private InterpretationResponse parseInterpretation(String json) { try { JsonObject obj = gson.fromJson(json, JsonObject.class); InterpretationResponse resp = new InterpretationResponse(); // 解析 sections JsonArray sectionsArr = obj.getAsJsonArray("sections"); List sections = new ArrayList<>(); for (JsonElement el : sectionsArr) { JsonObject s = el.getAsJsonObject(); InterpretationResponse.Section section = new InterpretationResponse.Section(); section.title = getString(s, "title", ""); section.positions = getStringArray(s, "positions"); section.values = getIntArray(s, "values"); section.content = getString(s, "content", ""); section.keywords = getStringArray(s, "keywords"); sections.add(section); } resp.sections = sections; // 解析 summary resp.summary = getString(obj, "summary", ""); // 解析 combinationNotes resp.combinationNotes = getStringArray(obj, "combinationNotes"); // 校验:至少有一个 section 且有 content if (resp.sections.isEmpty() || resp.sections.stream().allMatch(s -> s.content.isEmpty())) { return null; // 触发降级 } return resp; } catch (Exception e) { return null; } } ``` #### InterpretationResponse DTO ```java package com.etotem.num.service; import java.util.List; public class InterpretationResponse { public List
sections; public String summary; public List combinationNotes; public static class Section { public String title; public List positions; public List values; public String content; public List keywords; } } ``` #### ChartController.java 现有端点适配 ```java /** * 获取能量盘 AI 解读(US-3.1) * 首次调用触发 Dify Workflow,后续走缓存(US-3.3) */ @PostMapping("/chart/interpret") public Result interpret(@RequestBody Map body) { Long userId = (Long) request.getAttribute("userId"); if (userId == null) return Result.error(1001, "请先登录"); Long chartRecordId = ((Number) body.get("chartRecordId")).longValue(); String interpretation = chartService.getInterpretation(chartRecordId); return Result.success(interpretation); } ``` #### ChartService.java 解读生成与缓存(US-3.3) ```java @Service public class ChartService { @Autowired private DifyService difyService; @Autowired private ChartRecordRepository chartRecordRepository; /** * 获取能量盘解读(优先缓存) */ public String getInterpretation(Long chartRecordId) { ChartRecord record = chartRecordRepository.findById(chartRecordId); // 1. 检查缓存(US-3.3) if (record.getInterpretation() != null) { return record.getInterpretation(); } // 2. 调用 Dify Workflow String chartContext = buildChartContext(record); InterpretationResponse resp = difyService.interpretChart( chartContext, record.getUserName(), record.getBirthday().toString() ); // 3. 序列化为 JSON 字符串 String json = new Gson().toJson(resp); // 4. 缓存到数据库 record.setInterpretation(json); chartRecordRepository.save(record); return json; } /** * 重新生成解读(覆盖缓存,US-3.3.3) */ @Transactional public String regenerateInterpretation(Long chartRecordId) { ChartRecord record = chartRecordRepository.findById(chartRecordId); record.setInterpretation(null); // 清除缓存 return getInterpretation(chartRecordId); // 重新生成 } private String buildChartContext(ChartRecord record) { Map ctx = new HashMap<>(); ctx.put("positions", record.getChartData()); ctx.put("zones", record.getZones()); ctx.put("mainCharacter", record.getMainCharacter()); ctx.put("isMasterNumber", record.getIsMasterNumber()); ctx.put("userName", record.getUserName()); ctx.put("birthday", record.getBirthday().toString()); return new Gson().toJson(ctx); } } ``` ### 9.8 错误处理与降级 | 场景 | 处理方式 | 用户可见消息 | |------|---------|------------| | Workflow 超时 >15s | 重试 1 次 → 降级到 mock | "解读生成较慢,已返回简要分析" | | 非 JSON 输出 | 重试 1 次 → 降级到 mock | —(静默降级) | | sections 为空 | 降级到 mock,记录告警 | "暂时无法获取完整解读" | | Dify 4xx 错误 | 记录错误日志,降级到 mock | "解读服务暂时不可用,请稍后再试" | | Dify 5xx 错误 | 重试 1 次(1s 退避)→ 降级 | "解读服务繁忙,请稍后再试" | | 网络超时/断连 | 重试 1 次 → 降级 | "网络异常,请重试" | #### Mock 降级实现 ```java private InterpretationResponse generateMockInterpretation( String chartContext, String userName, String birthday) { InterpretationResponse resp = new InterpretationResponse(); resp.sections = new ArrayList<>(); // 从 chartContext 解析主性格数字 int mainChar = extractMainCharacter(chartContext); // 生成主性格概要 InterpretationResponse.Section main = new InterpretationResponse.Section(); main.title = "主性格解读"; main.positions = List.of("O"); main.values = List.of(mainChar); main.content = "你的主性格数字 " + mainChar + "。" + NUMBER_DESC.getOrDefault(mainChar, "独特能量组合"); main.keywords = List.of("主性格", "核心能量"); resp.sections.add(main); resp.summary = "详细解读正在生成中,请稍后再试或联系客服。"; resp.combinationNotes = new ArrayList<>(); return resp; } ``` ### 9.9 Dify 控制台配置步骤 1. **登录 Dify** → 点击「创建应用」→ 选择「Workflow」 2. **命名应用**:`能量盘解读` 3. **配置 START 节点**:添加 3 个输入变量 - `chart_context`(String, JSON) - `user_name`(String) - `birthday`(String) 4. **添加 KB 检索节点 1**(主性格): - 数据集:选择 `数字能量学知识库`(ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`) - Top-K:`3` - 检索查询:`主性格数字 {{chart_context.positions.O}} 含义 性格 特质 优势 挑战 成长` 5. **添加 KB 检索节点 2**(左区): - 相同数据集,Top-K:`3` - 检索查询:`左区 21-40岁 {{chart_context.positions.P}} {{chart_context.positions.Q}} {{chart_context.positions.R}} 组合 发展` 6. **添加 KB 检索节点 3**(顶部): - 相同数据集,Top-K:`3` - 检索查询:`顶部 41-60岁 {{chart_context.positions.V}} {{chart_context.positions.W}} {{chart_context.positions.X}} 中年 事业` 7. **添加 KB 检索节点 4**(右区): - 相同数据集,Top-K:`3` - 检索查询:`右区 61岁 {{chart_context.positions.S}} {{chart_context.positions.T}} {{chart_context.positions.U}} 晚年 财运` 8. **添加 KB 检索节点 5**(特殊组合): - 相同数据集,Top-K:`3` - 检索查询:`组合 八星 {{chart_context.positions.I}}{{chart_context.positions.J}} {{chart_context.positions.M}}{{chart_context.positions.N}} 能量` 9. **将 KB 1-5 节点并行连接至 LLM 节点** 10. **配置 LLM 节点**: - 模型:Claude 3.5 Sonnet - Temperature:`0.6` - Max Tokens:`3000` - System Prompt:粘贴第 9.5 节的完整提示词 - 上下文变量引用:将所有 5 个 KB 检索节点的输出和 `chart_context` 变量作为上下文引用 11. **添加代码节点**:粘贴第 9.4 节 Node 7 的 Python 代码 12. **连接代码节点至 END 节点** 13. **点击「发布」**,记录生成的 API Key(用于 `application.yml` 的 `dify.workflow-api-key`) ### 9.10 与 Chatflow 的差异对比 | 维度 | Chatflow(AI问答) | Workflow(能量盘解读) | |------|--------------------|---------------------| | 用途 | 多轮自由问答 | 一次性能量盘全盘解读 | | 输出格式 | 自然语言(`answer` 字段) | 结构化 JSON(sections + summary) | | 记忆 | 6 轮对话记忆(Dify 维护) | 无记忆,每次独立执行 | | 触发时机 | 用户输入问题 | 能量盘创建后自动触发 | | 调用频率 | 用户每次提问 | 每个能量盘仅 1 次(后续走缓存) | | 输入变量 | `chart_context` + `query` | `chart_context` + `user_name` + `birthday` | | KB 检索数 | 1 个检索节点(按需) | 5 个并行检索节点 | | API 端点 | `POST /v1/chat-messages` | `POST /v1/workflows/run` | | 响应模式 | streaming(打字机效果) | blocking(同步等待) | | 超时设置 | 30s | 15s |