modelfunction-cli 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/cases.js +50 -2
- package/lib/lint.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx -y modelfunction-cli@0.1.
|
|
8
|
+
npx -y modelfunction-cli@0.1.3 --version
|
|
9
9
|
# 或
|
|
10
10
|
npm i -D modelfunction-cli
|
|
11
11
|
npx mf --version
|
|
@@ -83,7 +83,7 @@ INTERNAL_LLM_KEY=... mf eval --suite mf.suite.json \
|
|
|
83
83
|
"mcpServers": {
|
|
84
84
|
"modelfunction": {
|
|
85
85
|
"command": "npx",
|
|
86
|
-
"args": ["-y", "modelfunction-cli@0.1.
|
|
86
|
+
"args": ["-y", "modelfunction-cli@0.1.3", "mcp"]
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -105,7 +105,7 @@ INTERNAL_LLM_KEY=... mf eval --suite mf.suite.json \
|
|
|
105
105
|
|
|
106
106
|
```bash
|
|
107
107
|
# 1. 把 mf 挂成 MCP server
|
|
108
|
-
claude mcp add modelfunction -- npx -y modelfunction-cli@0.1.
|
|
108
|
+
claude mcp add modelfunction -- npx -y modelfunction-cli@0.1.3 mcp
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
```text
|
package/lib/cases.js
CHANGED
|
@@ -167,15 +167,63 @@ export function suspectedPairs(tools) {
|
|
|
167
167
|
if (union.size === 0) continue;
|
|
168
168
|
let shared = 0;
|
|
169
169
|
for (const token of union) if (a.has(token) && b.has(token)) shared += 1;
|
|
170
|
-
const
|
|
170
|
+
const lexical = shared / union.size;
|
|
171
|
+
const structural = structuralScore(tools[i], tools[j]);
|
|
172
|
+
const similarity = Math.max(lexical, structural);
|
|
171
173
|
if (similarity >= PAIR_SIMILARITY) {
|
|
172
|
-
pairs.push({
|
|
174
|
+
pairs.push({
|
|
175
|
+
a: tools[i].name,
|
|
176
|
+
b: tools[j].name,
|
|
177
|
+
similarity,
|
|
178
|
+
basis: structural > lexical ? "structural" : "lexical"
|
|
179
|
+
});
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
182
|
}
|
|
176
183
|
return pairs.sort((x, y) => y.similarity - x.similarity);
|
|
177
184
|
}
|
|
178
185
|
|
|
186
|
+
// Tools that share part of the name (search / file / read...) and the same
|
|
187
|
+
// parameter shape confuse the model even when the wording differs, which the
|
|
188
|
+
// lexical score alone misses. Name order is unreliable: `tavily_search` leads
|
|
189
|
+
// with the vendor, `search_docs` with the action.
|
|
190
|
+
function structuralScore(x, y) {
|
|
191
|
+
const left = nameTokens(x.name);
|
|
192
|
+
const right = nameTokens(y.name);
|
|
193
|
+
const sharedName = left.some((token) => right.includes(token));
|
|
194
|
+
if (!sharedName) return 0;
|
|
195
|
+
const params = paramNames(x);
|
|
196
|
+
const otherParams = paramNames(y);
|
|
197
|
+
if (params.size === 0 && otherParams.size === 0) return 0;
|
|
198
|
+
const paramOverlap = jaccard(params, otherParams);
|
|
199
|
+
if (paramOverlap < 0.34) return 0;
|
|
200
|
+
const requiredOverlap = jaccard(
|
|
201
|
+
new Set(x.parameters?.required ?? []),
|
|
202
|
+
new Set(y.parameters?.required ?? [])
|
|
203
|
+
);
|
|
204
|
+
return 0.5 + 0.5 * (0.6 * paramOverlap + 0.4 * requiredOverlap);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function nameTokens(name) {
|
|
208
|
+
return String(name ?? "")
|
|
209
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
210
|
+
.toLowerCase()
|
|
211
|
+
.split(/[^a-z0-9]+/)
|
|
212
|
+
.filter(Boolean);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function paramNames(tool) {
|
|
216
|
+
return new Set(Object.keys(tool.parameters?.properties ?? {}));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function jaccard(a, b) {
|
|
220
|
+
if (a.size === 0 && b.size === 0) return 1;
|
|
221
|
+
const union = new Set([...a, ...b]);
|
|
222
|
+
let shared = 0;
|
|
223
|
+
for (const item of union) if (a.has(item) && b.has(item)) shared += 1;
|
|
224
|
+
return shared / union.size;
|
|
225
|
+
}
|
|
226
|
+
|
|
179
227
|
function tokens(text) {
|
|
180
228
|
const set = new Set();
|
|
181
229
|
const lowered = String(text ?? "").toLowerCase();
|
package/lib/lint.js
CHANGED
|
@@ -178,7 +178,8 @@ export function lintSuite(suite) {
|
|
|
178
178
|
pair: [pair.a, pair.b]
|
|
179
179
|
});
|
|
180
180
|
} else if (pair.similarity >= NO_BOUNDARY_SIMILARITY) {
|
|
181
|
-
|
|
181
|
+
const reason = pair.basis === "structural" ? "名字与参数形状接近" : "描述相近";
|
|
182
|
+
add("warn", "pair-no-boundary", pair.a, `与 ${pair.b} ${reason}(相似度 ${similarity}),且两边都没写“不适用于”边界,模型只能靠相似度硬猜`, {
|
|
182
183
|
pair: [pair.a, pair.b],
|
|
183
184
|
suggestion: `在 ${pair.a} 和 ${pair.b} 的 description 里各写一句“不适用于什么”,并补一条歧义用例`
|
|
184
185
|
});
|