@josephyan/qingflow-app-user-mcp 1.0.8 → 1.1.1
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 +6 -2
- package/npm/bin/qingflow-app-user-mcp.mjs +31 -2
- package/npm/lib/runtime.mjs +43 -2
- package/package.json +1 -1
- package/pyproject.toml +2 -1
- package/skills/qingflow-app-builder/SKILL.md +276 -0
- package/skills/qingflow-app-builder/agents/openai.yaml +4 -0
- package/skills/qingflow-app-builder/references/build-complete-system.md +428 -0
- package/skills/qingflow-app-builder/references/build-single-app.md +530 -0
- package/skills/qingflow-app-builder/references/create-app.md +149 -0
- package/skills/qingflow-app-builder/references/environments.md +63 -0
- package/skills/qingflow-app-builder/references/flow-actors-and-permissions.md +123 -0
- package/skills/qingflow-app-builder/references/gotchas.md +108 -0
- package/skills/qingflow-app-builder/references/match-rules.md +114 -0
- package/skills/qingflow-app-builder/references/public-surface-sync.md +75 -0
- package/skills/qingflow-app-builder/references/solution-playbooks.md +52 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +107 -0
- package/skills/qingflow-app-builder/references/update-flow.md +186 -0
- package/skills/qingflow-app-builder/references/update-layout.md +68 -0
- package/skills/qingflow-app-builder/references/update-schema.md +72 -0
- package/skills/qingflow-app-builder/references/update-views.md +291 -0
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +137 -0
- package/skills/qingflow-app-builder-code-integrations/agents/openai.yaml +4 -0
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +66 -0
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +77 -0
- package/skills/qingflow-app-user/SKILL.md +2 -1
- package/skills/qingflow-app-user/references/data-gotchas.md +5 -3
- package/skills/qingflow-app-user/references/public-surface-sync.md +6 -3
- package/skills/qingflow-app-user/references/record-patterns.md +14 -4
- package/skills/qingflow-mcp-setup/SKILL.md +111 -0
- package/skills/qingflow-mcp-setup/agents/openai.yaml +4 -0
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +34 -0
- package/skills/qingflow-mcp-setup/references/environments.md +61 -0
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +31 -0
- package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +38 -0
- package/skills/qingflow-record-analysis/SKILL.md +94 -183
- package/skills/qingflow-record-analysis/agents/openai.yaml +2 -2
- package/skills/qingflow-record-analysis/references/analysis-gotchas.md +54 -111
- package/skills/qingflow-record-analysis/references/analysis-patterns.md +96 -131
- package/skills/qingflow-record-analysis/references/business-context.md +74 -0
- package/skills/qingflow-record-analysis/references/confidence-reporting.md +49 -74
- package/skills/qingflow-record-analysis/references/data-access-playbook.md +106 -0
- package/skills/qingflow-record-analysis/references/pandas-recipes.md +172 -0
- package/skills/qingflow-record-analysis/references/report-format.md +76 -0
- package/skills/qingflow-record-insert/SKILL.md +28 -7
- package/skills/qingflow-record-update/SKILL.md +3 -1
- package/skills/qingflow-workflow-builder/SKILL.md +96 -0
- package/skills/qingflow-workflow-builder/manifest.yaml +8 -0
- package/skills/qingflow-workflow-builder/references/01-overview.md +45 -0
- package/skills/qingflow-workflow-builder/references/02-update-mode.md +53 -0
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +57 -0
- package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +131 -0
- package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +29 -0
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +165 -0
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +33 -0
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +51 -0
- package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +88 -0
- package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +93 -0
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +15 -0
- package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +275 -0
- package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +605 -0
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/backend_client.py +55 -1
- package/src/qingflow_mcp/builder_facade/models.py +532 -48
- package/src/qingflow_mcp/builder_facade/service.py +9194 -2384
- package/src/qingflow_mcp/builder_facade/workflow_spec.py +111 -0
- package/src/qingflow_mcp/cli/commands/app.py +3 -16
- package/src/qingflow_mcp/cli/commands/builder.py +354 -56
- package/src/qingflow_mcp/cli/commands/record.py +112 -6
- package/src/qingflow_mcp/cli/formatters.py +133 -2
- package/src/qingflow_mcp/cli/main.py +204 -3
- package/src/qingflow_mcp/public_surface.py +12 -9
- package/src/qingflow_mcp/response_trim.py +288 -22
- package/src/qingflow_mcp/server.py +29 -20
- package/src/qingflow_mcp/server_app_builder.py +108 -30
- package/src/qingflow_mcp/server_app_user.py +29 -23
- package/src/qingflow_mcp/solution/compiler/__init__.py +1 -3
- package/src/qingflow_mcp/solution/compiler/icon_utils.py +294 -0
- package/src/qingflow_mcp/solution/executor.py +3 -133
- package/src/qingflow_mcp/tools/ai_builder_tools.py +2617 -440
- package/src/qingflow_mcp/tools/app_tools.py +53 -8
- package/src/qingflow_mcp/tools/package_tools.py +16 -2
- package/src/qingflow_mcp/tools/record_tools.py +14451 -9110
- package/src/qingflow_mcp/tools/resource_read_tools.py +3 -0
- package/src/qingflow_mcp/tools/solution_tools.py +30 -2
- package/src/qingflow_mcp/tools/workflow_tools.py +3 -31
- package/skills/qingflow-record-analysis/references/dsl-templates.md +0 -93
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +0 -173
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
ROOT="${QINGFLOW_MCP_ROOT:-}"
|
|
6
|
+
|
|
7
|
+
if [[ -z "$ROOT" ]]; then
|
|
8
|
+
if git_root="$(git rev-parse --show-toplevel 2>/dev/null)" && [[ -d "$git_root/qingflow-support/mcp-server" ]]; then
|
|
9
|
+
ROOT="$git_root/qingflow-support/mcp-server"
|
|
10
|
+
elif [[ -d "$PWD/qingflow-support/mcp-server" ]]; then
|
|
11
|
+
ROOT="$PWD/qingflow-support/mcp-server"
|
|
12
|
+
else
|
|
13
|
+
repo_root="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
|
14
|
+
if [[ -d "$repo_root/qingflow-support/mcp-server" ]]; then
|
|
15
|
+
ROOT="$repo_root/qingflow-support/mcp-server"
|
|
16
|
+
fi
|
|
17
|
+
fi
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
if [[ -z "$ROOT" ]]; then
|
|
21
|
+
echo "Unable to locate qingflow-support/mcp-server. Set QINGFLOW_MCP_ROOT to the repo copy of the MCP server." >&2
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
ENTRY="$ROOT/qingflow-mcp"
|
|
26
|
+
PY="$ROOT/.venv/bin/python"
|
|
27
|
+
|
|
28
|
+
echo "ROOT=$ROOT"
|
|
29
|
+
test -d "$ROOT"
|
|
30
|
+
echo "OK root exists"
|
|
31
|
+
|
|
32
|
+
test -x "$ENTRY"
|
|
33
|
+
echo "OK entrypoint exists and is executable"
|
|
34
|
+
|
|
35
|
+
test -x "$PY"
|
|
36
|
+
echo "OK virtualenv python exists"
|
|
37
|
+
|
|
38
|
+
PYTHONPATH="$ROOT/src" "$PY" -c "import qingflow_mcp.server; print('OK import qingflow_mcp.server')"
|
|
@@ -1,67 +1,71 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qingflow-record-analysis
|
|
3
|
-
description: Analyze Qingflow record data safely after the MCP is already connected and authenticated. Use when the user wants grouped distributions, ratios, averages, rankings, trends, insights, or any final statistical conclusion across an existing app's data.
|
|
3
|
+
description: Analyze Qingflow record data safely after the MCP is already connected and authenticated. Use when the user wants grouped distributions, ratios, averages, rankings, trends, insights, comparisons, or any final statistical conclusion across an existing app's data. Default to schema-first record_access CSV retrieval plus local Python/pandas; do not use export tools unless the user explicitly asks for a file download.
|
|
4
4
|
metadata:
|
|
5
|
-
short-description: Analyze Qingflow record data with
|
|
5
|
+
short-description: Analyze Qingflow record data with record_access CSV and Python
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Qingflow Record Analysis
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
Assumes MCP is connected, authenticated, and on the correct workspace.
|
|
12
|
-
Analysis tasks must start with `app_get`, then `record_browse_schema_get(view_id=...)`. `record_browse_schema_get.fields` is the selected Qingflow table view's readable header schema and is the same field source used by `record_access.fields` / `schema.json`. Read top-level `fields` and `suggested_*`, then choose field_id-based columns and filters only.
|
|
13
|
-
If `app_get.accessible_views` marks a view with `analysis_supported=false`, do not use that view for `record_access`, `record_list`, or `record_analyze`. `boardView` and `ganttView` are special UI views, not data-access targets.
|
|
10
|
+
Use this skill only for final statistical conclusions: counts, distributions, ratios, averages, rankings, trends, comparisons, and analysis reports.
|
|
14
11
|
|
|
15
|
-
|
|
12
|
+
Default path, every time:
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
## Execution Modes
|
|
22
|
-
|
|
23
|
-
Choose the lightest mode that can still support a trustworthy conclusion:
|
|
24
|
-
|
|
25
|
-
1. `client_python_from_record_access`
|
|
26
|
-
- Default and preferred path
|
|
27
|
-
- Use `record_access` directly after `app_get -> record_browse_schema_get`
|
|
28
|
-
- Read CSV shard files from `files[].local_path` with Python
|
|
29
|
-
- Treat `complete=true` and `safe_for_final_conclusion=true` as required before giving a full-scope final conclusion
|
|
30
|
-
|
|
31
|
-
2. `lightweight_record_analyze`
|
|
32
|
-
- Optional helper for small grouped summaries or quick sanity checks
|
|
33
|
-
- Still requires `app_get -> record_browse_schema_get` first
|
|
34
|
-
- Do not make this the default agent path
|
|
35
|
-
|
|
36
|
-
3. `cross_app_manual_reconcile`
|
|
37
|
-
- Use when the question depends on joining multiple apps, organization-history alias mapping, or other business logic that current public tools do not express directly
|
|
38
|
-
- Be explicit that the conclusion is based on manual reconciliation rules, not one single app's CSV access
|
|
39
|
-
|
|
40
|
-
## Fallback Ladder
|
|
41
|
-
|
|
42
|
-
Trigger a fallback when any of these are true:
|
|
43
|
-
|
|
44
|
-
- `record_access` returns `complete=false`, `truncated=true`, or `safe_for_final_conclusion=false`
|
|
45
|
-
- the target view is unsupported for data access
|
|
46
|
-
- field semantics are ambiguous enough that local aggregation would be misleading
|
|
47
|
-
- the question requires cross-app reconciliation
|
|
48
|
-
- the question depends on organization-tree scope, historical department aliases, or other business rules that are not first-class MCP filters
|
|
49
|
-
|
|
50
|
-
When you fall back:
|
|
51
|
-
|
|
52
|
-
1. Keep the standard read order: `app_get -> record_browse_schema_get`
|
|
53
|
-
2. State which fallback mode you chose
|
|
54
|
-
3. State whether the result is still full-scope or only a verified subset
|
|
55
|
-
4. State the time field, organization scope, and any alias mapping used
|
|
56
|
-
5. Prefer concrete numbers plus a conservative conclusion over broad wording
|
|
57
|
-
|
|
58
|
-
---
|
|
14
|
+
```text
|
|
15
|
+
app_get -> record_browse_schema_get(view_id=...) -> record_access -> Python/pandas -> final answer
|
|
16
|
+
```
|
|
59
17
|
|
|
60
|
-
|
|
18
|
+
`record_access` may appear either as an MCP tool or as a CLI subcommand. If the active client does not expose an MCP `record_access` tool, do not switch to aggregate helpers. Use the CLI entry instead:
|
|
61
19
|
|
|
62
|
-
|
|
20
|
+
```bash
|
|
21
|
+
qingflow record --help
|
|
22
|
+
qingflow record access --help
|
|
23
|
+
qingflow record access --app-key APP_KEY --view-id VIEW_ID --columns-file columns.json --where-file where.json --order-by-file order_by.json --json
|
|
24
|
+
```
|
|
63
25
|
|
|
64
|
-
|
|
26
|
+
The CLI command is under the `record` command group, so the discovery path is: first inspect `qingflow record --help`, then inspect `qingflow record access --help`.
|
|
27
|
+
|
|
28
|
+
## Hard Rules
|
|
29
|
+
|
|
30
|
+
- Never start analysis from `record_list`, export, QingBI, or guessed field ids.
|
|
31
|
+
- Never conclude `record_access` is unavailable just because it is not visible as a top-level MCP tool; check the CLI path `qingflow record access`.
|
|
32
|
+
- Never call `record_access` before `record_browse_schema_get`.
|
|
33
|
+
- Use only field ids returned by `record_browse_schema_get.fields`.
|
|
34
|
+
- If `app_get.accessible_views[].analysis_supported=false`, do not use that view for `record_access`.
|
|
35
|
+
- Prefer an explicit time range or business filter. If the user gives none and the table may be large, ask for scope or use a clearly provided month/quarter/year.
|
|
36
|
+
- Read every CSV shard in `record_access.files[].local_path` with Python. Do not print raw CSV or load raw rows into model context.
|
|
37
|
+
- Before final analysis, run a field-quality profile in pandas: row count, null rate, distinct count, and period coverage for candidate grouping fields.
|
|
38
|
+
- Do not use a high-missing field as the main conclusion dimension. If a candidate dimension is sparse, downgrade it to an `已填写样本观察` and choose a cleaner semantic fallback when available.
|
|
39
|
+
- Full final conclusions require `record_access.complete=true` and `record_access.safe_for_final_conclusion=true`.
|
|
40
|
+
- `record_list` is only for sample inspection after the aggregate result is understood.
|
|
41
|
+
- `record_get` is only for single-record detail verification, logs, references, images, or readable attachments. Read images from `media_assets.items[].local_path`; read documents/tables from `file_assets.items[].local_path` and `extraction.text_path`.
|
|
42
|
+
- `record_export_direct` is only for explicit export/download/Excel requests.
|
|
43
|
+
- `chart_get` / QingBI is only for user-provided report URLs or chart ids.
|
|
44
|
+
|
|
45
|
+
## Tool Selection
|
|
46
|
+
|
|
47
|
+
| Need | Tool |
|
|
48
|
+
|---|---|
|
|
49
|
+
| Batch analysis, statistics, comparison, report | `record_access -> Python` |
|
|
50
|
+
| Browse a few example rows | `record_list` |
|
|
51
|
+
| Inspect one record, logs, references, images, attachments | `record_get` |
|
|
52
|
+
| User asks to export/download/Excel | `record_export_direct` |
|
|
53
|
+
| User gives report URL or chart id | `chart_get` |
|
|
54
|
+
| Todo/workflow task actions | `$qingflow-task-ops` |
|
|
55
|
+
|
|
56
|
+
## Standard Procedure
|
|
57
|
+
|
|
58
|
+
1. Run `app_get` and choose a table-style `view_id` from `accessible_views`.
|
|
59
|
+
2. Run `record_browse_schema_get(app_key, view_id)`.
|
|
60
|
+
3. Decide metric intent before fetching data: `count`, `sum`, `avg`, `distinct_count`, ratio, ranking, trend, or comparison.
|
|
61
|
+
4. Choose minimal `record_access.columns`, plus `where` and `order_by`.
|
|
62
|
+
5. Run `record_access` through MCP if visible, otherwise through `qingflow record access`.
|
|
63
|
+
6. Read all returned CSV files in Python; use `fields[]` only when field-id metadata is needed.
|
|
64
|
+
7. Run field-quality checks for all candidate dimensions.
|
|
65
|
+
8. Compute results in pandas.
|
|
66
|
+
9. Report numbers with scope, field choices, field-quality caveats, completeness, and business assumptions.
|
|
67
|
+
|
|
68
|
+
Use field-id DSLs only:
|
|
65
69
|
|
|
66
70
|
```json
|
|
67
71
|
{
|
|
@@ -73,154 +77,61 @@ Use `record_access` to fetch detail rows into local CSV shards. It does not anal
|
|
|
73
77
|
}
|
|
74
78
|
```
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
- Never ask for `page`, `page_size`, `limit`, or `max_rows`; `record_access` owns paging internally and follows the backend's native paging capability.
|
|
79
|
-
- Never treat backend `searchQueIds` as column selection; it is only a full-text search scope.
|
|
80
|
-
- If multiple CSV files are returned, read them all.
|
|
81
|
-
- If `complete=false` or `safe_for_final_conclusion=false`, downgrade the answer and disclose the limitation.
|
|
82
|
-
- `record_export_direct` is only for explicit export/download/Excel requests, not default analysis.
|
|
83
|
-
- QingBI/report reads are only for user-provided report URLs or `chart_id`; do not create or use reports as the default analysis path.
|
|
84
|
-
|
|
85
|
-
### `record_analyze` Lightweight DSL
|
|
80
|
+
Never pass `page`, `page_size`, `limit`, `max_rows`, `timeout`, or `profile` to `record_access`.
|
|
86
81
|
|
|
87
|
-
|
|
82
|
+
CSV columns are already readable and field-id anchored, for example `项目状态__field_343283094`. Do not expect separate `schema.json` or `README.md` files.
|
|
88
83
|
|
|
89
|
-
|
|
84
|
+
For CLI use, write JSON argument files instead of embedding large JSON in shell text:
|
|
90
85
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
```bash
|
|
87
|
+
qingflow record access \
|
|
88
|
+
--app-key APP_KEY \
|
|
89
|
+
--view-id system:all \
|
|
90
|
+
--columns-file columns.json \
|
|
91
|
+
--where-file where.json \
|
|
92
|
+
--order-by-file order_by.json \
|
|
93
|
+
--json
|
|
97
94
|
```
|
|
98
95
|
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
✅ CORRECT: { "op": "count", "alias": "记录数" }
|
|
102
|
-
✅ CORRECT: { "op": "sum", "field_id": 7, "alias": "总金额" }
|
|
103
|
-
❌ WRONG: { "type": "count" } ← "type" is NOT a valid key
|
|
104
|
-
❌ WRONG: { "agg": "count" } ← "agg" is NOT a valid key
|
|
105
|
-
❌ WRONG: { "aggregation": "count" } ← "aggregation" is NOT a valid key
|
|
106
|
-
```
|
|
96
|
+
## Status Handling
|
|
107
97
|
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
✅ CORRECT: { "field_id": 2, "op": "between", "value": ["2024-03-01", "2024-03-31"] }
|
|
111
|
-
✅ CORRECT: { "field_id": 5, "op": "eq", "value": "已完成" }
|
|
112
|
-
❌ WRONG: { "field_id": 2, "operator": "between", "value": [...] } ← "operator" is forbidden
|
|
113
|
-
❌ WRONG: { "field_id": 2, "op": ">=", "value": "2024-03-01" } ← ">=" is not valid, use "gte"
|
|
114
|
-
```
|
|
98
|
+
Read `record_access.status` before reading files or writing conclusions.
|
|
115
99
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
```
|
|
100
|
+
- `status=success`, `complete=true`, `safe_for_final_conclusion=true`: full-scope answer is allowed.
|
|
101
|
+
- `status=needs_scope`: no CSV was written. Ask for a time/business range or retry with a user-provided period using `scope.suggested_time_fields`.
|
|
102
|
+
- `status=partial`: read returned files only as a subset. Do not give a full-population conclusion.
|
|
103
|
+
- `complete=false`, `truncated=true`, or `safe_for_final_conclusion=false`: answer as `初步观察` or ask for a narrower scope.
|
|
121
104
|
|
|
122
|
-
|
|
105
|
+
## Business Context
|
|
123
106
|
|
|
124
|
-
|
|
125
|
-
|------|-------------------|
|
|
126
|
-
| dimension | `field_id`, `alias`, `bucket` |
|
|
127
|
-
| metric | `op`, `field_id`, `alias` |
|
|
128
|
-
| filter | `field_id`, `op`, `value` |
|
|
129
|
-
| sort | `by`, `order` |
|
|
107
|
+
If the question mentions department, team, region, owner group, stage, product line, or a named business scope, check whether aliases or child scopes matter before concluding. Use explicit mappings provided by the user or local context; otherwise ask a short clarification.
|
|
130
108
|
|
|
131
|
-
|
|
109
|
+
Example: if `烈焰组` and `飓风组` are sub-departments of `北斗部门`, apply that mapping in Python and state it in the answer.
|
|
132
110
|
|
|
133
|
-
|
|
134
|
-
- filters: `eq`, `neq`, `in`, `not_in`, `gt`, `gte`, `lt`, `lte`, `between`, `contains`, `is_null`, `not_null`
|
|
135
|
-
- For `count` metric: do NOT pass `field_id`. For all others: `field_id` is required.
|
|
136
|
-
- If `metrics` is omitted or `[]`, defaults to `[{"op":"count","alias":"记录数"}]`.
|
|
111
|
+
## Output Shape
|
|
137
112
|
|
|
138
|
-
|
|
113
|
+
Default to:
|
|
139
114
|
|
|
140
|
-
|
|
115
|
+
1. `结论`
|
|
116
|
+
2. `关键数据`
|
|
117
|
+
3. `口径与范围`
|
|
118
|
+
4. `可信度 / 限制`
|
|
141
119
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
{
|
|
145
|
-
"dimensions": [{ "field_id": FIELD_ID_FROM_SCHEMA, "alias": "维度名" }],
|
|
146
|
-
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
147
|
-
"sort": [{ "by": "记录数", "order": "desc" }],
|
|
148
|
-
"limit": 50,
|
|
149
|
-
"strict_full": true
|
|
150
|
-
}
|
|
151
|
-
```
|
|
120
|
+
Concrete numbers are mandatory. Ratios require both numerator and denominator. Trends require a time field and explicit date range. Rankings must come from a sorted pandas result.
|
|
121
|
+
If a requested dimension has poor quality, say so explicitly and provide the nearest reliable fallback dimension, for example platform or product instead of a mostly empty module field.
|
|
152
122
|
|
|
153
|
-
|
|
154
|
-
```json
|
|
155
|
-
{
|
|
156
|
-
"dimensions": [{ "field_id": TIME_FIELD_ID, "alias": "月份", "bucket": "month" }],
|
|
157
|
-
"metrics": [{ "op": "count", "alias": "记录数" }],
|
|
158
|
-
"filters": [{ "field_id": TIME_FIELD_ID, "op": "between", "value": ["2024-03-01", "2024-03-31"] }],
|
|
159
|
-
"sort": [{ "by": "月份", "order": "asc" }],
|
|
160
|
-
"limit": 24,
|
|
161
|
-
"strict_full": true
|
|
162
|
-
}
|
|
163
|
-
```
|
|
123
|
+
## References
|
|
164
124
|
|
|
165
|
-
|
|
125
|
+
Load only what is needed:
|
|
166
126
|
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
- `bucket` in dimensions: only for `suggested_time_fields`. Values: `day`/`week`/`month`/`quarter`/`year`/`null`.
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## RULES
|
|
179
|
-
|
|
180
|
-
- 渗透率 / 转化率 / 占比类结论必须先定义分子和分母。
|
|
181
|
-
- Do not claim a metric you did not query.
|
|
182
|
-
- Derived ratios must be computed outside the DSL.
|
|
183
|
-
- Before choosing a DSL shape, first decide whether the question needs `count`, `sum`, `avg`, `distinct_count`, `ratio`, or `ranking`.
|
|
184
|
-
- Rankings must come from structured sorted results.
|
|
185
|
-
- For partial answers, explicitly disclose which parts are complete and which parts remain unresolved.
|
|
186
|
-
- Complex answers should default to `先结构、后解读`.
|
|
187
|
-
- `between`: pass a two-item array.
|
|
188
|
-
- Sort entries must reference an alias already defined in `dimensions` or `metrics`.
|
|
189
|
-
- Final wording should stay as close as possible to schema titles.
|
|
190
|
-
- Do not pass field titles, aliases, or guessed ids.
|
|
191
|
-
- If `completeness.statement_scope=returned_groups_only` or `completeness.rows_truncated=true`, downgrade wording to returned groups only.
|
|
192
|
-
- One data-access request per coherent dataset. Multiple small Python computations over the same CSV files are fine.
|
|
193
|
-
- `record_list` is not the basis for final statistics. Use it only for browse/sample inspection and disclose that scope if quoted.
|
|
194
|
-
- Set `alias` for any metric you will sort by, compare, or quote.
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
## OUTPUT
|
|
199
|
-
|
|
200
|
-
- Final answer must show concrete numbers.
|
|
201
|
-
- Final answer must state which execution mode was used whenever the answer is not the default `client_python_from_record_access`
|
|
202
|
-
- If `result.rows` exists, list each returned row; if there are more than 20 rows, show Top 20 and say so.
|
|
203
|
-
- 占比 = 行指标值 / `result.totals.metric_totals` 总值;如 `metric_totals` 缺失,用各行之和作分母。
|
|
204
|
-
- Prefer the structured `ranking` block when it exists.
|
|
205
|
-
- `safe_for_final_conclusion=true` → `全量可信结论`
|
|
206
|
-
- Otherwise → `初步观察`
|
|
207
|
-
- `rows_truncated=true` → 用 `前 N 个分组`, 不用 `全部`/`所有`
|
|
208
|
-
- If you used a fallback mode or `record_access.safe_for_final_conclusion=false`, explicitly disclose:
|
|
209
|
-
- whether this is full-scope or a manually curated subset
|
|
210
|
-
- which time field was used
|
|
211
|
-
- which organization scope was used
|
|
212
|
-
- whether any historical department aliases or cross-app joins were applied
|
|
127
|
+
- Data access status machine: [references/data-access-playbook.md](references/data-access-playbook.md)
|
|
128
|
+
- Python/pandas templates: [references/pandas-recipes.md](references/pandas-recipes.md)
|
|
129
|
+
- Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
|
|
130
|
+
- Business mappings and scope: [references/business-context.md](references/business-context.md)
|
|
131
|
+
- Confidence and final wording: [references/confidence-reporting.md](references/confidence-reporting.md)
|
|
132
|
+
- Common mistakes: [references/analysis-gotchas.md](references/analysis-gotchas.md)
|
|
133
|
+
- Report templates: [references/report-format.md](references/report-format.md)
|
|
213
134
|
|
|
214
135
|
## Feedback Escalation
|
|
215
136
|
|
|
216
|
-
|
|
217
|
-
- Ask whether the user wants you to submit product feedback.
|
|
218
|
-
- Only after explicit user confirmation, call `feedback_submit`.
|
|
219
|
-
|
|
220
|
-
## Resources
|
|
221
|
-
|
|
222
|
-
- Shared public-surface baseline: [public-surface-sync.md](../qingflow-app-user/references/public-surface-sync.md)
|
|
223
|
-
- DSL templates: [references/dsl-templates.md](references/dsl-templates.md)
|
|
224
|
-
- Analysis patterns: [references/analysis-patterns.md](references/analysis-patterns.md)
|
|
225
|
-
- Confidence reporting: [references/confidence-reporting.md](references/confidence-reporting.md)
|
|
226
|
-
- Analysis gotchas: [references/analysis-gotchas.md](references/analysis-gotchas.md)
|
|
137
|
+
If the desired analysis cannot be completed because of missing capability, unsupported data shape, or an awkward workflow after reasonable attempts, summarize the exact gap and ask whether to submit product feedback. Only after explicit user confirmation, call `feedback_submit`.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Qingflow Record Analysis"
|
|
3
|
-
short_description: "Analyze Qingflow record data with
|
|
4
|
-
default_prompt: "Use $qingflow-record-analysis for grouped distributions, ratios, rankings, trends, and final statistical conclusions in Qingflow apps. Start with app_get and record_browse_schema_get, run record_access with field_id-based columns/where/order_by, then analyze
|
|
3
|
+
short_description: "Analyze Qingflow record data with record_access CSV and Python"
|
|
4
|
+
default_prompt: "Use $qingflow-record-analysis for grouped distributions, ratios, rankings, trends, and final statistical conclusions in Qingflow apps. Start with app_get and record_browse_schema_get, run record_access with field_id-based columns/where/order_by, then analyze every returned CSV shard with Python. Always run field-quality checks before choosing final grouping dimensions, and downgrade sparse dimensions to filled-sample observations. If record_access is not visible as an MCP tool, discover and use the CLI path qingflow record --help -> qingflow record access --help. Treat record_list as sample-only."
|
|
@@ -1,148 +1,91 @@
|
|
|
1
1
|
# Analysis Gotchas
|
|
2
2
|
|
|
3
|
-
## Do
|
|
3
|
+
## Do Not Skip Schema
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Correct recovery:
|
|
5
|
+
Correct path:
|
|
8
6
|
|
|
9
7
|
1. `app_get`
|
|
10
8
|
2. `record_browse_schema_get`
|
|
11
|
-
3.
|
|
12
|
-
4.
|
|
13
|
-
5. use Python over the returned CSV shards
|
|
14
|
-
|
|
15
|
-
The schema here is applicant-node visible-only. If a field is absent, treat it as not available to the current user rather than switching to guessed ids or builder-side memory.
|
|
16
|
-
|
|
17
|
-
## Normalize relative time phrases before building the DSL.
|
|
18
|
-
|
|
19
|
-
Examples:
|
|
20
|
-
|
|
21
|
-
- `最近一个完整自然月` -> convert to an explicit full-month date range
|
|
22
|
-
- `上个月` -> convert to a concrete month range
|
|
23
|
-
- `最近30天` -> convert to exact start/end dates
|
|
24
|
-
|
|
25
|
-
Do not pass vague time phrases or impossible dates into MCP.
|
|
26
|
-
|
|
27
|
-
## Do not treat paged list output as full data
|
|
28
|
-
|
|
29
|
-
`record_list` can hit:
|
|
30
|
-
|
|
31
|
-
- `row_cap=200`
|
|
32
|
-
- `row_cap_hit=true`
|
|
33
|
-
- `sample_only=true`
|
|
34
|
-
|
|
35
|
-
When this happens, it is sample-only evidence.
|
|
36
|
-
|
|
37
|
-
It is not acceptable to use that result alone for:
|
|
9
|
+
3. `record_access`
|
|
10
|
+
4. Python
|
|
38
11
|
|
|
39
|
-
-
|
|
40
|
-
- 占比
|
|
41
|
-
- 排名
|
|
42
|
-
- 趋势
|
|
43
|
-
- 地域分布
|
|
44
|
-
- “基于全部数据”的 business insight
|
|
12
|
+
`record_browse_schema_get` returns readable fields for the selected view. Missing fields are permission or view-scope boundaries, not invitations to guess hidden ids.
|
|
45
13
|
|
|
46
|
-
## Do
|
|
14
|
+
## Do Not Use Export For Analysis
|
|
47
15
|
|
|
48
|
-
|
|
16
|
+
Export tools are for user-requested files. Analysis uses `record_access` because it returns structured completeness and compact field metadata.
|
|
49
17
|
|
|
50
|
-
|
|
18
|
+
## Do Not Treat `record_list` As Full Data
|
|
51
19
|
|
|
52
|
-
|
|
53
|
-
- `样本观察`
|
|
20
|
+
`record_list` is sample/browse only. It can be capped and should not justify:
|
|
54
21
|
|
|
55
|
-
|
|
22
|
+
- average
|
|
23
|
+
- share
|
|
24
|
+
- ranking
|
|
25
|
+
- trend
|
|
26
|
+
- regional distribution
|
|
27
|
+
- "all data" insights
|
|
56
28
|
|
|
57
|
-
|
|
29
|
+
## Do Not Control Paging
|
|
58
30
|
|
|
59
|
-
|
|
60
|
-
- do not say `所有分组`
|
|
61
|
-
- do not say `完整名单`
|
|
31
|
+
`record_access` owns paging internally.
|
|
62
32
|
|
|
63
|
-
|
|
33
|
+
Do not invent:
|
|
64
34
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
35
|
+
- `page`
|
|
36
|
+
- `page_size`
|
|
37
|
+
- `limit`
|
|
38
|
+
- `requested_pages`
|
|
39
|
+
- `scan_max_pages`
|
|
40
|
+
- `max_rows`
|
|
41
|
+
- `timeout`
|
|
67
42
|
|
|
68
|
-
## Do
|
|
43
|
+
## Do Not Print Raw CSV
|
|
69
44
|
|
|
70
|
-
|
|
45
|
+
Read CSV files with pandas. Summarize computed results, not raw rows.
|
|
71
46
|
|
|
72
|
-
|
|
73
|
-
- do not guess ids
|
|
74
|
-
- do not switch from one read tool to another by trial and error
|
|
75
|
-
- do not keep retrying different guessed field names in a loop
|
|
47
|
+
## Do Not Rename Source Files
|
|
76
48
|
|
|
77
|
-
|
|
49
|
+
CSV columns are directly readable and field-id anchored: `record_id`, `<字段标题>__field_<id>`. Use those columns directly in pandas.
|
|
78
50
|
|
|
79
|
-
|
|
80
|
-
2. if several plausible candidates remain, ask the user to confirm from a short list
|
|
81
|
-
3. build the DSL only after the field is clear
|
|
51
|
+
## Do Not Trust Sparse Dimensions
|
|
82
52
|
|
|
83
|
-
|
|
53
|
+
Before final grouping, run a field-quality profile. If the selected field is mostly blank, say so and downgrade the claim.
|
|
84
54
|
|
|
85
|
-
|
|
55
|
+
Rules of thumb:
|
|
86
56
|
|
|
87
|
-
-
|
|
88
|
-
-
|
|
57
|
+
- Overall blank rate above 40%: not a primary conclusion dimension.
|
|
58
|
+
- Any compared period blank rate above 80%: do not use that field for period comparison.
|
|
59
|
+
- A sparse field can support only `已填写样本观察`.
|
|
89
60
|
|
|
90
|
-
|
|
61
|
+
If the user asks for a semantic field such as `板块`, test nearby candidates like product, platform, module, stage, source, owner, or department before concluding.
|
|
91
62
|
|
|
92
|
-
|
|
63
|
+
## Do Not Hide Incomplete Access
|
|
93
64
|
|
|
94
|
-
|
|
95
|
-
- Do not invent `requested_pages`
|
|
96
|
-
- Do not invent `scan_max_pages`
|
|
97
|
-
- Do not rename CSV columns before analysis; use `metadata_files.schema` / `metadata_files.readme` to interpret `field_<id>` columns.
|
|
98
|
-
- Do not invent `auto_expand_pages`
|
|
99
|
-
- Do not invent `max_rows`
|
|
65
|
+
If `needs_scope`, no CSV exists. Ask for a time/business scope.
|
|
100
66
|
|
|
101
|
-
|
|
67
|
+
If `partial`, use only subset wording and avoid full-population claims.
|
|
102
68
|
|
|
103
|
-
|
|
104
|
-
2. reduce the analysis problem into smaller field_id-based access requests
|
|
105
|
-
3. keep the answer at `初步观察` or `部分结果` if completeness is still not enough
|
|
69
|
+
If field meaning is ambiguous, ask the user to confirm from a short list.
|
|
106
70
|
|
|
107
|
-
## Do
|
|
71
|
+
## Do Not Guess Metrics
|
|
108
72
|
|
|
109
|
-
Before
|
|
73
|
+
Before fetching data, decide whether the request needs count, sum, average, distinct count, ratio, ranking, trend, or comparison.
|
|
110
74
|
|
|
111
|
-
|
|
112
|
-
- `sum`
|
|
113
|
-
- `avg`
|
|
114
|
-
- `distinct_count`
|
|
115
|
-
- a ratio with numerator + denominator
|
|
116
|
-
- a sorted ranking result
|
|
75
|
+
## Do Not Call A Ratio Without Denominator
|
|
117
76
|
|
|
118
|
-
|
|
77
|
+
For penetration, conversion, or share:
|
|
119
78
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
- say which parts are still unresolved
|
|
126
|
-
- do not present the answer as fully finished
|
|
127
|
-
|
|
128
|
-
## Do not send unsupported formula or div-style metrics into `record_analyze`.
|
|
129
|
-
|
|
130
|
-
Examples to avoid:
|
|
131
|
-
|
|
132
|
-
- `{"op":"div", ...}`
|
|
133
|
-
- metric items with `formula`, `expr`, `numerator`, or `denominator`
|
|
134
|
-
|
|
135
|
-
Correct recovery:
|
|
136
|
-
|
|
137
|
-
1. query the source metrics with separate DSLs
|
|
138
|
-
2. confirm both sides are complete and compatible
|
|
139
|
-
3. compute the derived ratio outside MCP in the reasoning layer
|
|
79
|
+
1. define numerator
|
|
80
|
+
2. define denominator
|
|
81
|
+
3. query compatible source data
|
|
82
|
+
4. compute in Python
|
|
83
|
+
5. report numerator and denominator
|
|
140
84
|
|
|
141
|
-
##
|
|
85
|
+
## Normalize Relative Dates
|
|
142
86
|
|
|
143
|
-
|
|
87
|
+
Convert relative phrases into exact ranges before `record_access`.
|
|
144
88
|
|
|
145
|
-
1
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
4. only then compute and report the ratio
|
|
89
|
+
- `今年5月` -> exact May 1 to May 31 in the current year
|
|
90
|
+
- `去年同期` -> same date range in previous year
|
|
91
|
+
- `最近30天` -> exact rolling start/end dates
|