Install any skill in seconds. Free to start, no credit card required.
Get Started Free →采用诊断式对话风格。先倾听客户问题,必要时通过追问收集关键信息(如错误信息、环境配置、操作步骤),然后基于内置知识库给出解答。回答要具体、可操作,复杂问题提供步骤指引。</core_approach>
.claude/skills/data-mini-faq/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | — | — |
| case-06 | ✗→✓ | ▲ Improved | — | — |
| case-02 | ✗→✓ | ▲ Improved | — | — |
| case-15 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
<core_approach> 采用诊断式对话风格。先倾听客户问题,必要时通过追问收集关键信息(如错误信息、环境配置、操作步骤),然后基于内置知识库给出解答。回答要具体、可操作,复杂问题提供步骤指引。</core_approach>
<workflow>
</workflow>
<reference>
;trustServerCertificate=true| 表达式 | 说明 | |--------|------| | $.store.book].author | 获取所有书籍作者 | | $..author | 获取所有作者 | | $.store..price | 获取所有价格 | | $..book2] | 获取第三本书 | | $..book?(@.price<10)] | 价格小于10的书 | | $..book?(@.category=="fiction")] | 分类为fiction的书 |
| 表达式 | 说明 | |--------|------| | /messages/message | 所有message节点 | | //message@id=1] | id=1的message | | //local-name()='标签名'] | 任意命名空间下的节点 | | //text() | 所有文本节点 |
系统使用LiteFlow工作流引擎,支持两种脚本语言:
Context上下文(Java获取):
javaContext context = this.getContextBean(Context.class);
Context常用方法: | 方法 | 说明 | |------|------| | context.getSourceResult() | 获取当前线程的输入结果 | | context.getPrevResult() | 获取上一步输入结果 | | context.getSourceResult(name) | 通过名称获取输入结果 | | context.setSourceResult(result) | 设置当前输入结果(仅用于mock数据、给原数据加字段场景) | | context.setPrevResult(result) | 设置上一步输入结果(循环内分批处理场景) | | context.set(key, value) | 设置上下文参数(最常用,传递给后续组件) | | context.get(key) | 获取上下文参数 | | context.log() | 打印日志 |
循环索引:
this.getLoopIndex() - 获取当前循环索引(从0开始)| 场景 | 脚本写法 | |------|----------| | 设置参数给输入/输出组件用 | context.set("参数名", 值) | | Mock测试数据 | context.setSourceResult(...) | | 给原始数据添加字段 | context.setPrevResult(...) | | 循环内分批处理数据 | ForScript返回次数,Script内用offsetList分批,用ForSourceResult返回 |
LiteFlow中循环场景通常需要两个脚本配合使用:循环脚本 返回总次数,设置参数脚本 在每次循环中设置具体参数。
脚本(设置起止日期) → ForScript(日期列表) → Script(设置当前日期参数) → 输入 → 输出输入(获取列表) → ForScript(行数循环) → Script(取出当前行参数) → 输入(查明细) → 输出输入(获取总页数) → ForScript(页数循环) → Script(设置当前页号) → 输入(查询当前页) → 输出ForScript(固定100次) → Script(设置页号) → 输入(查询) → Script(无数据跳出) → 输出输入 → ForScript(分批次数) → Script(处理当前批次) → 输出| 类型 | 说明 | 接口 | |------|------|------| | for_script | 循环脚本 | 继承NodeForComponent,实现processFor()返回循环次数 | | script | 普通脚本 | 继承NodeComponent,实现process() | | boolean_script | 布尔脚本 | 继承NodeBooleanComponent,实现processBoolean()返回boolean |
编写脚本时如需使用工具类库(特别是 hutool),请先查阅在线文档:
常用 hutool 类:
cn.hutool.json - JSON处理(JSONObject, JSONArray, JSONUtil)cn.hutool.core.date - 日期处理(DateUtil, DateTime)cn.hutool.core.convert - 类型转换(Convert)cn.hutool.crypto - 加密解密(HMac, HmacAlgorithm, Base64)以下脚本需要配对使用,给客户返回时需同时提供两个脚本。
场景:按天循环同步一段时间数据,防止单次数据量过大
循环脚本(ForScript):
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeForComponent; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateTime; import java.util.ArrayList; import java.util.List; public class DateListForComp extends NodeForComponent { @Override public int processFor() throws Exception { Context context = this.getContextBean(Context.class); String startDate = String.valueOf(context.get("start_date")); String endDate = String.valueOf(context.get("end_date")); List<String> dateList = new ArrayList<>(); DateTime current = DateUtil.parse(startDate, "yyyy-MM-dd"); DateTime end = DateUtil.parse(endDate, "yyyy-MM-dd"); while (!current.isAfter(end)) { dateList.add(current.toString("yyyy-MM-dd")); current = current.offsetNew(1, cn.hutool.core.date.DateField.DAY_OF_MONTH); } context.set("dateList", dateList); return dateList.size() - 1; } }
设置参数脚本(Script):
javaimport java.util.List; import com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class DateListParamsComp extends NodeComponent { @Override public void process() throws Exception { Context context = this.getContextBean(Context.class); List<String> dateList = (List<String>) context.get("dateList"); int idx = this.getLoopIndex(); context.set("start_date", dateList.get(idx)); context.set("end_date", dateList.get(idx + 1)); } }
场景:循环列表中每行数据,用某字段作为参数查明细
循环脚本(ForScript):
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeForComponent; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; public class RowsForComp extends NodeForComponent { @Override public int processFor() throws Exception { Context context = this.getContextBean(Context.class); JSONArray list = context.getSourceResult().toJSONList(); for (int i = 0; i < list.size(); i++) { JSONObject row = JSONUtil.parseObj(list.get(i)); context.set(String.valueOf(i), row); } return list.size(); } }
设置参数脚本(Script):
javaimport cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class AddRowParamComp extends NodeComponent { @Override public void process() { Context context = this.getContextBean(Context.class); int loopIndex = this.getLoopIndex(); JSONObject row = JSONUtil.parseObj(context.get(String.valueOf(loopIndex))); context.set("lsh", row.get("lsh")); // 设置需要查询的参数 } }
场景:已知总页数,循环遍历每一页
循环脚本(ForScript):
javaimport cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeForComponent; public class PageCountForComp extends NodeForComponent { @Override public int processFor() throws Exception { Context context = this.getContextBean(Context.class); JSONArray list = context.getSourceResult().toJSONList(); if (list == null || list.isEmpty()) { return 0; } JSONObject row = JSONUtil.parseObj(list.get(0)); return row.getInt("page_count", 0); } }
设置参数脚本(Script):
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class AddPageNoParamComp extends NodeComponent { @Override public void process() { Context context = this.getContextBean(Context.class); context.set("page_no", String.valueOf(this.getLoopIndex() + 1)); } }
场景:未知总页数,用固定次数循环+无数据跳出
循环脚本(ForScript):
javaimport com.yomahub.liteflow.core.NodeForComponent; public class FixedNumberForComp extends NodeForComponent { @Override public int processFor() throws Exception { return 100; } }
设置参数脚本1 - 设置页号(Script):
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class AddPageNoParamComp extends NodeComponent { @Override public void process() { Context context = this.getContextBean(Context.class); context.set("page_no", String.valueOf(this.getLoopIndex() + 1)); } }
设置参数脚本2 - 无数据跳出(Script):
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class BreakThrowExceptionComp extends NodeComponent { @Override public void process() throws Exception { Context context = this.getContextBean(Context.class); if (context.getPrevResult() == null || context.getPrevResult().getCount() == 0) { throw new RuntimeException("输入无数据,跳出循环"); } } }
场景:大数据量输入,分批处理防止内存溢出
循环脚本(ForScript):
javaimport com.creating.matrix.data.mini.model.Context; import com.creating.matrix.data.mini.model.SourceResult; import com.yomahub.liteflow.core.NodeForComponent; public class DemoForComponent extends NodeForComponent { @Override public int processFor() throws Exception { Context context = this.getContextBean(Context.class); SourceResult sr = context.getSourceResult(); return sr != null ? (sr.getCount() / 500 + 1) : 0; } }
处理脚本(Script):
javaimport cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.core.date.DateUtil; import com.creating.matrix.data.mini.model.ForSourceResult; import com.creating.matrix.data.mini.model.Context; import com.creating.matrix.data.mini.model.SourceResult; import com.yomahub.liteflow.core.NodeComponent; public class DemoComp extends NodeComponent { @Override public void process() throws Exception { Context context = this.getContextBean(Context.class); SourceResult sr = context.getSourceResult(); JSONArray list = sr.offsetList(500); for (Object item : list) { ((JSONObject)item).set("now", DateUtil.now()); } context.setPrevResult(ForSourceResult.builder().loopIndex(this.getLoopIndex()).rows(list).build()); } }
以下脚本可单独使用。
JavaScript脚本:
javascriptvar now = new Date(); var today = now.getFullYear() + '-' + (now.getMonth() + 1).toString().padStart(2, '0') + '-' + now.getDate().toString().padStart(2, '0'); var yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000); var yesterdayStr = yesterday.getFullYear() + '-' + (yesterday.getMonth() + 1).toString().padStart(2, '0') + '-' + yesterday.getDate().toString().padStart(2, '0'); context.set("start_date", yesterdayStr); context.set("end_date", today);
javaimport cn.hutool.core.codec.Base64; import cn.hutool.crypto.digest.HMac; import cn.hutool.crypto.digest.HmacAlgorithm; import com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class AddEncoding extends NodeComponent { @Override public void process() { Context context = this.getContextBean(Context.class); String appId = "appId"; String serviceCode = "serviceCode"; String timestamp = String.valueOf(System.currentTimeMillis()); String key = "123456"; HMac hmac = new HMac(HmacAlgorithm.HmacSHA1, key.getBytes()); byte[] digest = hmac.digest("appId="+appId+"&serviceCode="+serviceCode+"×tamp="+timestamp); String str = Base64.encode(digest); context.set("base64Str", str); context.set("timestamp", timestamp); context.log(str); } }
JavaScript脚本:
javascriptvar DateUtil = Java.type("cn.hutool.core.date.DateUtil"); var JSONSourceResult = Java.type("com.creating.matrix.data.mini.model.JSONSourceResult"); var list = context.getSourceResult().toJSONList(); for (var i = 0; i < list.size(); i++) { list.get(i).set("now", DateUtil.now()); } context.setPrevResult(JSONSourceResult.builder().rows(list).build());
javaimport com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeBooleanComponent; public class AddEncoding11 extends NodeBooleanComponent { @Override public boolean processBoolean() { Context context = this.getContextBean(Context.class); Object lx = context.get("lx"); return lx != null && String.valueOf(lx).contains("zd"); } }
JavaScript脚本,用于测试:
javascriptvar JSONUtil = Java.type("cn.hutool.json.JSONUtil"); var HTTPSourceResult = Java.type("com.creating.matrix.data.mini.model.HTTPSourceResult"); var demoData = []; for (var i = 1; i <= 2000; i++) { demoData.push({ id: i, name: 'User ' + i, age: Math.floor(Math.random() * 50) + 20, hobbies: ['Reading', 'Sports', 'Coding', 'Music'][Math.floor(Math.random() * 4)] }); } context.setSourceResult(HTTPSourceResult.builder().rows(JSONUtil.parseArray(JSON.stringify(demoData))).build());
JavaScript脚本:
javascriptcontext.log();
javaimport cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.creating.matrix.data.mini.model.Context; import com.yomahub.liteflow.core.NodeComponent; public class DemoComp extends NodeComponent { @Override public void process() throws Exception { Context context = this.getContextBean(Context.class); JSONArray jsonList1 = context.getSourceResult("基本信息查询").toJSONList(); JSONArray jsonList2 = context.getSourceResult("诊断查询").toJSONList(); context.getSourceResult("基本信息查询").close(); context.getSourceResult("诊断查询").close(); JSONObject jsonObject1 = new JSONObject(); jsonObject1.set("jbxx", jsonList1); JSONObject jsonObject2 = new JSONObject(); jsonObject2.set("zd", jsonList2); context.set("jbxx", JSONUtil.toXmlStr(jsonObject1)); context.set("zds", JSONUtil.toXmlStr(jsonObject2)); } }
</reference>
<examples>
答:这是因为数据库元数据缓存了旧的表结构。解决方法:重新打开JDBC输出的修改弹框,预览SQL确认正确后保存一下,这样会更新缓存。
答:在调度配置中使用CRON表达式,如每天0点执行用"0 0 "。流程:添加调度→选择任务→配置CRON表达式→保存。
答:通常是XML包含命名空间导致。先用 //local-name()='标签名'] 语法测试能否获取到节点,如果可以就在配置中用此语法或者替换掉XML中的命名空间字符串。 </examples>
<quality_checklist>
</quality_checklist>
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-23 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-24 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +63 percentage points is the difference between those two pass rates over the 24 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.