Skip to content

Commit a1fd963

Browse files
os-zhuangclaude
andcommitted
feat(service-ai): steer the agent to visualize_data for chart requests
Small models (e.g. claude-haiku) sometimes answered a "draw a bar chart" request with a markdown TABLE — running query_data/aggregate_data and formatting the numbers — instead of calling visualize_data. This was a tool-selection problem, not a capability gap: the chart preference was buried as guideline #7 and competed with guideline #4 ("format with markdown tables"). - data-explorer-skill.ts: add a prominent "Choosing the right tool" section ABOVE the guidelines — chart intent (incl. CN terms 图表/柱状图/折线图/饼图/画图) → MUST call visualize_data; never substitute a table; reconcile the table-formatting guideline; fix duplicate guideline numbering. - visualize-data.tool.ts: strengthen the tool description to be imperative ("the ONLY tool that draws a chart… you MUST call this, not a table; if you already fetched the numbers, still call visualize_data to render them"). Prompt-only tuning — no behavior/contract change. Raises the likelihood the model reaches for visualize_data on a plain chart request without an explicit "use visualize_data" nudge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a5cd791 commit a1fd963

2 files changed

Lines changed: 17 additions & 10 deletions

File tree

packages/services/service-ai/src/skills/data-explorer-skill.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,18 @@ Capabilities:
2727
- Perform aggregations and statistical analysis (count, sum, avg, min, max)
2828
- Render results as a CHART when a visualization communicates the answer better than text
2929
30+
Choosing the right tool (decide this BEFORE querying):
31+
- The user wants a CHART — they say "chart/plot/graph/visualize/draw", "图表/柱状图/折线图/饼图/画图/可视化", OR they ask to show/compare/break down a count or sum grouped by a category, OR a trend over time → you MUST call visualize_data. It is the ONLY tool that draws a chart; query_data/aggregate_data return numbers, never a chart. Do NOT answer a chart request with a markdown table. If you already fetched the numbers, still call visualize_data to render them. The chart shows inline automatically — afterwards reply with one or two sentences describing it; do NOT re-print the numbers as a table.
32+
- The user wants the underlying records or a single number → query_data / query_records / aggregate_data.
33+
3034
Guidelines:
3135
1. Always use the describe_object tool first to understand a table's structure before querying it.
3236
2. Do NOT assume generic fields like \`status\`, \`is_active\`, \`deleted_at\`, \`type\`, or \`enabled\` exist on every object — they almost never do. Field names in \`where\`, \`fields\`, \`orderBy\`, \`groupBy\`, and aggregations MUST come from describe_object output. If the tool returns an "Unknown field" error, call describe_object on that object and retry with real field names.
3337
3. Respect the user's current context — if they are viewing a specific object or record, use that as the default scope.
34-
4. When presenting data, format it in a clear and readable way using markdown tables or bullet lists.
38+
4. For record lists or a plain numeric answer, format clearly with markdown tables or bullet lists. When a chart was requested, use visualize_data instead of a table (see "Choosing the right tool" above).
3539
5. For large result sets, summarize the data and mention the total count.
3640
6. When performing aggregations, explain the results in plain language.
37-
7. Prefer the visualize_data tool when the user asks to "chart", "plot", "graph", "visualize", or "show a breakdown/trend/distribution", or whenever a count/sum grouped by a category (or a trend over time) is the answer. The chart renders inline automatically — after calling it, just describe briefly what the chart shows; do NOT also dump the raw numbers as a table.
38-
8. If a query returns no results, suggest possible reasons and alternative queries.
41+
7. If a query returns no results, suggest possible reasons and alternative queries.
3942
8. Never expose internal IDs unless the user explicitly asks for them.
4043
9. Always answer in the same language the user is using.`,
4144
tools: [

packages/services/service-ai/src/tools/visualize-data.tool.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,17 @@ export const VISUALIZE_DATA_TOOL: AIToolDefinition = {
117117
name: 'visualize_data',
118118
label: 'Visualize Data (Chart)',
119119
description:
120-
'Aggregate a data object and render the result as a CHART in the chat. ' +
121-
'Use this — instead of query_records / aggregate_data — whenever the ' +
122-
'best answer is a visualization (counts/sums grouped by a category, a ' +
123-
'trend over time, a distribution, etc.). The chart is shown to the user ' +
124-
'automatically; you only need to briefly describe what it shows. ' +
125-
'Field names in `dimension`, `measures[].field` and `where` MUST be real ' +
126-
'fields obtained from describe_object — do NOT guess generic names.',
120+
'Aggregate a data object and render the result as a CHART shown inline in ' +
121+
'the chat. This is the ONLY tool that draws a chart. You MUST call this — ' +
122+
'NOT query_records / aggregate_data, and NOT a markdown table — whenever ' +
123+
'the user asks to chart/plot/graph/visualize/draw data, or to show, ' +
124+
'compare, or break down a count or sum grouped by a category, or a trend ' +
125+
'over time. If you already fetched the numbers with another tool, still ' +
126+
'call visualize_data to render them. After it runs the chart is shown to ' +
127+
'the user automatically; reply with one or two sentences describing it and ' +
128+
'do NOT re-print the data as a table. Field names in `dimension`, ' +
129+
'`measures[].field` and `where` MUST be real fields obtained from ' +
130+
'describe_object — do NOT guess generic names.',
127131
parameters: {
128132
type: 'object',
129133
properties: {

0 commit comments

Comments
 (0)