A BI Developer Bolted a Natural-Language AI Assistant Onto SmartBI in One Day Without Writing a Single Line of Frontend Code
Done! No frontend skills, spent one day installing an AI agent on the company's BI system!
As a BI/data developer, I've always had a pain point: business people have to come to me every time they need data, asking me to write SQL and drag reports. Simple questions like sales amounts and regional sales volumes get repeated dozens of times a day. I've always wanted to add a natural language data query AI assistant to the company's SmartBI system, but the thought of writing a frontend chat interface, doing backend APIs, handling server deployment, and dealing with cross-origin authentication always felt like too much trouble, so I put it off for over half a year.
Until I recently discovered EdgeOne Makers. From registering an account to getting it running locally, and then embedding a floating window into SmartBI, it took a total of one day. I didn't write a single line of frontend code and got the AI agent installed. This article lays out the complete steps and all the pitfalls I encountered; you can follow along and succeed too.
I want to share this case because from start to finish, I was just copying and pasting, and basically, AI helped me check and correct errors. The moment I finally got the agent working successfully, my scalp tingled. EdgeOne Makers is just too good!!!
Let's first look at the final effect~
1. Complete Implementation Steps from Zero to One (Follow Along and You'll Succeed)
Preparation
- A computer that can run Python (Windows/Mac both work)
- A Tencent Cloud account (the free tier is sufficient)
- Access to your company's BI system intranet environment
Step 1: Create an EdgeOne Makers Project
- Open the EdgeOne Makers console: https://edgeone.cloud.tencent.com/makers
2. Create a new project and select the 'OpenAI Agents Starter Template (Python version)'
- Choose a git platform; I chose Gitee here, then click 'Create Now'.
- Wait 1 minute, and the project is initialized. It comes with a chat interface, session memory, streaming output, and a tool-calling framework. No need to write your own frontend.
Step 2: Set Up the Local Development Environment
- First, install the EdgeOne CLI tool:
npm install -g edgeone
- Pull the project locally and enter the project directory.
- Install dependencies:
npm install
- Windows users must set the encoding first (otherwise, emojis will cause a GBK encoding error later):
set PYTHONUTF8=1
- Start the local development service:
edgeone makers dev
- After a successful start, open http://localhost:8088 to see the default chat interface, which comes with sample tools like weather and translation. The startup is slow; wait until you see 'running at xxx'.
Step 3: Configure SmartBI Environment Variables
Create a .env file in the project root directory and configure the SmartBI connection information:
# AI Gateway Configuration (auto-generated after project creation, no need to change)
AI_GATEWAY_API_KEY=your_API_KEY
AI_GATEWAY_BASE_URL=your_gateway_address
AI_GATEWAY_MODEL=@makers/deepseek-v4-flash
# SmartBI Configuration
SMARTBI_BASE_URL=http://your_SmartBI_address:port/smartbi
SMARTBI_TOKEN=your_SmartBI_personal_access_token
PYTHONUTF8=1
Generate the SmartBI personal access token in 'Personal Center - Personal Access Token'; query permissions are sufficient. ⬇️⬇️⬇️
In the data model section, add a test dataset for subsequent agent testing.
-- Sales test data (Oracle version, UNION ALL constructs a temporary dataset, all fields in Chinese)
SELECT
"Order Date",
"Order Number",
"Region",
"Province",
"City",
"Product Category",
"Product Name",
"Sales Quantity",
"Unit Price",
"Sales Amount",
"Profit",
"Customer Type",
"Sales Channel",
"Salesperson"
FROM (
-- January Sales Data
SELECT DATE '2026-01-05' AS "Order Date", 'DD20260105001' AS "Order Number", 'East China' AS "Region", 'Jiangsu' AS "Province", 'Nanjing' AS "City",
'Fish Products' AS "Product Category", 'Spicy Small Dried Fish' AS "Product Name", 120 AS "Sales Quantity", 3.5 AS "Unit Price",
420.00 AS "Sales Amount", 126.00 AS "Profit", 'Old Customer' AS "Customer Type", 'Distributor' AS "Sales Channel", 'Zhang San' AS "Salesperson" from dual
UNION ALL
SELECT DATE '2026-01-08', 'DD20260108001', 'South China', 'Guangdong', 'Guangzhou',
'Bean Products', 'Saucy Thick Dried Tofu', 200, 2.8, 560.00, 156.80, 'New Customer', 'Online', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-01-12', 'DD20260112001', 'North China', 'Beijing', 'Beijing',
'Meat Snacks', 'Spicy Dried Meat', 80, 5.0, 400.00, 120.00, 'Old Customer', 'Offline', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-01-15', 'DD20260115001', 'Southwest', 'Sichuan', 'Chengdu',
'Vegetarian Snacks', 'Konjac Shuang', 150, 2.5, 375.00, 105.00, 'Old Customer', 'Distributor', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-01-20', 'DD20260120001', 'Central China', 'Hunan', 'Changsha',
'Fish Products', 'Braised Small Dried Fish', 300, 3.5, 1050.00, 315.00, 'New Customer', 'Online', 'Zhang San' from dual
-- February Sales Data
UNION ALL
SELECT DATE '2026-02-03', 'DD20260203001', 'East China', 'Shanghai', 'Shanghai',
'Meat Snacks', 'Five-Spice Dried Meat', 100, 5.0, 500.00, 150.00, 'Old Customer', 'Offline', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-02-07', 'DD20260207001', 'South China', 'Guangdong', 'Shenzhen',
'Fish Products', 'Sweet and Sour Small Dried Fish', 180, 3.5, 630.00, 189.00, 'Old Customer', 'Online', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-02-12', 'DD20260212001', 'North China', 'Shandong', 'Jinan',
'Bean Products', 'Spicy Thick Dried Tofu', 250, 2.8, 700.00, 196.00, 'New Customer', 'Distributor', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-02-18', 'DD20260218001', 'Southwest', 'Chongqing', 'Chongqing',
'Vegetarian Snacks', 'Sour and Spicy Kelp Knots', 160, 2.0, 320.00, 89.60, 'Old Customer', 'Online', 'Zhang San' from dual
UNION ALL
SELECT DATE '2026-02-25', 'DD20260225001', 'Central China', 'Hubei', 'Wuhan',
'Fish Products', 'Spicy Small Dried Fish', 220, 3.5, 770.00, 231.00, 'Old Customer', 'Offline', 'Li Si' from dual
-- March Sales Data
UNION ALL
SELECT DATE '2026-03-02', 'DD20260302001', 'East China', 'Zhejiang', 'Hangzhou',
'Vegetarian Snacks', 'Spicy Konjac Shuang', 140, 2.5, 350.00, 98.00, 'New Customer', 'Online', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-03-09', 'DD20260309001', 'South China', 'Fujian', 'Fuzhou',
'Meat Snacks', 'Shredded Dried Meat', 90, 6.0, 540.00, 162.00, 'Old Customer', 'Distributor', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-03-15', 'DD20260315001', 'North China', 'Tianjin', 'Tianjin',
'Bean Products', 'Pickled Pepper Dried Tofu', 170, 2.8, 476.00, 133.28, 'Old Customer', 'Offline', 'Zhang San' from dual
UNION ALL
SELECT DATE '2026-03-20', 'DD20260320001', 'Southwest', 'Yunnan', 'Kunming',
'Fish Products', 'Braised Small Dried Fish', 110, 3.5, 385.00, 115.50, 'New Customer', 'Online', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-03-28', 'DD20260328001', 'Central China', 'Henan', 'Zhengzhou',
'Vegetarian Snacks', 'Crispy Lotus Root Slices', 200, 2.2, 440.00, 123.20, 'Old Customer', 'Distributor', 'Wang Wu' from dual
-- April Sales Data
UNION ALL
SELECT DATE '2026-04-04', 'DD20260404001', 'East China', 'Jiangsu', 'Suzhou',
'Fish Products', 'Spicy Small Dried Fish', 280, 3.5, 980.00, 294.00, 'Old Customer', 'Online', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-04-10', 'DD20260410001', 'South China', 'Guangdong', 'Dongguan',
'Meat Snacks', 'Spicy Dried Meat', 130, 5.0, 650.00, 195.00, 'New Customer', 'Offline', 'Zhang San' from dual
UNION ALL
SELECT DATE '2026-04-16', 'DD20260416001', 'North China', 'Hebei', 'Shijiazhuang',
'Bean Products', 'Five-Spice Dried Tofu', 210, 2.8, 588.00, 164.64, 'Old Customer', 'Distributor', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-04-22', 'DD20260422001', 'Southwest', 'Sichuan', 'Chengdu',
'Fish Products', 'Sweet and Sour Small Dried Fish', 190, 3.5, 665.00, 199.50, 'Old Customer', 'Online', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-04-29', 'DD20260429001', 'Central China', 'Hunan', 'Changsha',
'Vegetarian Snacks', 'Konjac Shuang', 320, 2.5, 800.00, 224.00, 'New Customer', 'Offline', 'Zhao Liu' from dual
-- May Sales Data
UNION ALL
SELECT DATE '2026-05-05', 'DD20260505001', 'East China', 'Shanghai', 'Shanghai',
'Meat Snacks', 'Shredded Dried Meat', 150, 6.0, 900.00, 270.00, 'Old Customer', 'Online', 'Zhang San' from dual
UNION ALL
SELECT DATE '2026-05-11', 'DD20260511001', 'South China', 'Guangxi', 'Nanning',
'Fish Products', 'Spicy Small Dried Fish', 160, 3.5, 560.00, 168.00, 'New Customer', 'Distributor', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-05-18', 'DD20260518001', 'North China', 'Beijing', 'Beijing',
'Vegetarian Snacks', 'Sour and Spicy Kelp Knots', 240, 2.0, 480.00, 134.40, 'Old Customer', 'Offline', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-05-23', 'DD20260523001', 'Southwest', 'Guizhou', 'Guiyang',
'Bean Products', 'Saucy Thick Dried Tofu', 130, 2.8, 364.00, 101.92, 'Old Customer', 'Online', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-05-30', 'DD20260530001', 'Central China', 'Jiangxi', 'Nanchang',
'Fish Products', 'Braised Small Dried Fish', 170, 3.5, 595.00, 178.50, 'New Customer', 'Distributor', 'Zhang San' from dual
-- June Sales Data
UNION ALL
SELECT DATE '2026-06-03', 'DD20260603001', 'East China', 'Zhejiang', 'Ningbo',
'Fish Products', 'Spicy Small Dried Fish', 260, 3.5, 910.00, 273.00, 'Old Customer', 'Offline', 'Li Si' from dual
UNION ALL
SELECT DATE '2026-06-08', 'DD20260608001', 'South China', 'Guangdong', 'Guangzhou',
'Meat Snacks', 'Five-Spice Dried Meat', 140, 5.0, 700.00, 210.00, 'Old Customer', 'Online', 'Wang Wu' from dual
UNION ALL
SELECT DATE '2026-06-15', 'DD20260615001', 'North China', 'Shandong', 'Qingdao',
'Vegetarian Snacks', 'Crispy Lotus Root Slices', 200, 2.2, 440.00, 123.20, 'New Customer', 'Distributor', 'Zhao Liu' from dual
UNION ALL
SELECT DATE '2026-06-21', 'DD20260621001', 'Southwest', 'Chongqing', 'Chongqing',
'Bean Products', 'Spicy Thick Dried Tofu', 280, 2.8, 784.00, 219.52, 'Old Customer', 'Online', 'Zhang San' from dual
UNION ALL
SELECT DATE '2026-06-28', 'DD20260628001', 'Central China', 'Hubei', 'Wuhan',
'Fish Products', 'Spicy Small Dried Fish', 350, 3.5, 1225.00, 367.50, 'Old Customer', 'Offline', 'Li Si' from dual
) t
Right-click the dataset to view its properties; you can see the dataset ID, which will be used later.
Step 4: Write the SmartBI Query Tool
Create a smartbi_tool.py file in the agents/chat/ directory. This is the core tool file; only two tools are needed:
import os
import json
import requests
from agents import function_tool
from typing import Annotated
SMARTBI_BASE_URL = os.getenv("SMARTBI_BASE_URL", "")
SMARTBI_TOKEN = os.getenv("SMARTBI_TOKEN", "")
def _get_headers():
return {
"Authorization": f"Bearer {SMARTBI_TOKEN}",
"Content-Type": "application/json"
}
# Tool 1: Get a list of all datasets
@function_tool
def list_datasets() -> str:
"""Get a list of all available datasets/data models in SmartBI"""
if not SMARTBI_TOKEN or not SMARTBI_BASE_URL:
return "Error: Environment variables not configured"
url = f"{SMARTBI_BASE_URL}/api/catalog/getCatalogElement/DEFAULT_TREENODE"
try:
resp = requests.post(url, headers=_get_headers(), timeout=30)
if resp.status_code != 200:
return f"Failed to get catalog, HTTP {resp.status_code}"
return json.dumps(resp.json(), ensure_ascii=False, indent=2)[:3000]
except Exception as e:
return f"Exception getting catalog: {str(e)}"
# Tool 2: Query data
@function_tool
def query_dataset(
dataset_id: Annotated[str, "Dataset ID"],
fields: Annotated[str, "Fields to query, separated by English commas, use Chinese names, e.g., Order Date, Region, Sales Amount"],
limit: Annotated[int, "Number of rows to return, default 20"] = 20
) -> str:
"""Query data from a specified dataset, using Chinese field names"""
if not SMARTBI_TOKEN or not SMARTBI_BASE_URL:
return "Error: Environment variables not configured"
safe_limit = min(limit, 100)
field_list = [f.strip() for f in fields.split(",") if f.strip()]
url = f"{SMARTBI_BASE_URL}/smartbix/api/augmentedQuery/data/"
payload = {
"dataSetId": dataset_id,
"rows": field_list,
"columns": [],
"filters": []
}
try:
resp = requests.post(url, json=payload, headers=_get_headers(), timeout=30)
if resp.status_code != 200:
return f"Query failed, HTTP {resp.status_code}: {resp.text[:500]}"
data = resp.json()
iterator = data.get("iterator", [])
result = []
for row in iterator[:safe_limit]:
obj = {}
for idx, cell in enumerate(row):
field_name = field_list[idx] if idx < len(field_list) else f"field_{idx}"
obj[field_name] = cell.get("displayValue") or cell.get("value")
result.append(obj)
return json.dumps({
"success": True,
"total": len(iterator),
"returned": len(result),
"data": result
}, ensure_ascii=False, indent=2)
except Exception as e:
return f"Query exception: {str(e)}"
TOOLS = [list_datasets, query_dataset]
Step 5: Configure the Agent
Modify agents/chat/index.py to register the tools we wrote and configure the prompt:
# Keep other imports unchanged, add the tool import
from .smartbi_tool import TOOLS as smartbi_tools
agent = Agent(
name="SmartBI Data Assistant",
instructions="""
You are a SmartBI data query assistant, helping users query data in the SmartBI system.
Workflow:
1. When a user asks a data-related question, first call list_datasets to see all available datasets.
2. After finding the corresponding dataset, directly call query_dataset to query the data.
3. Use Chinese for field names. Common fields include: Order Date, Order Number, Region, Province, City, Category, Product Name, Quantity, Unit Price, Sales Amount, Profit, Customer Type, Channel, Salesperson.
4. After a successful query, perform simple summary statistics on the data and return the results in natural language.
Notes:
- Do not call get_dataset_schema; query directly using Chinese field names.
- If a query fails, try again with a few other common fields.
- Bold key numbers.
""",
# Add our tools
tools=[get_weather, get_clothing_advice, translate_text, text_statistics] + smartbi_tools,
model=llm_model,
)
The other SSE streaming output code doesn't need to be changed; the template has already written it.
Step 6: Configure iframe Cross-Origin
Because the chat interface needs to be embedded into SmartBI via iframe, modify vite.config.ts to allow cross-origin and iframe embedding:
import { defineConfig } from 'vite'
export default defineConfig({
server: {
port: 8088,
host: '0.0.0.0',
headers: {
'X-Frame-Options': 'ALLOWALL',
'Content-Security-Policy': "frame-ancestors 'self' http://your_SmartBI_address:* http://localhost:*"
},
cors: true
}
})
Also modify index.html, adding a crypto polyfill at the very beginning of the head to be compatible with HTTP intranet environments:
<script>
if (!window.crypto) window.crypto = {};
if (!window.crypto.randomUUID) {
window.crypto.randomUUID = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
}
</script>
Step 7: Write the Floating Window Injection Script (No Need to Modify SmartBI Source Code)
The most convenient embedding method is a bookmarklet. No need to modify any SmartBI code, no need to install Tampermonkey. Just click a bookmark to bring up the floating window: (I'll explain why this method was chosen later; actually, the best way is to write the project code into SmartBI's index page.)
- Right-click on the browser's bookmark bar -> Add page
- Name:
AI Data Assistant - Paste the following complete code into the URL field (supports drag-to-resize from the top-left corner):
javascript:(function(){if(window.__aiAssistantLoaded)return;window.__aiAssistantLoaded=true;const AGENT_URL="http://your_local_IP:8088";let isOpen=false;let isResizing=false;let startX,startY,startW,startH;const btn=document.createElement('div');btn.innerHTML='💬 AI Data Assistant';btn.style.cssText='position:fixed;right:20px;bottom:20px;width:120px;height:44px;background:linear-gradient(135deg,#1677ff 0%,#722ed1 100%);color:white;border-radius:22px;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 16px rgba(22,119,255,0.4);z-index:999999;font-size:14px;font-weight:500;transition:all 0.3s;user-select:none;';const chatWindow=document.createElement('div');chatWindow.style.cssText='position:fixed;right:20px;bottom:76px;width:480px;height:680px;min-width:360px;min-height:480px;max-width:90vw;max-height:90vh;background:white;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.18);display:none;flex-direction:column;z-index:999998;overflow:hidden;';const resizeHandle=document.createElement('div');resizeHandle.style.cssText='position:absolute;left:0;top:0;width:20px;height:20px;cursor:nesw-resize;z-index:999999;background:linear-gradient(225deg,rgba(114,46,209,0.4) 0%,transparent 60%);border-radius:12px 0 0 0;';const header=document.createElement('div');header.style.cssText='padding:14px 16px;background:linear-gradient(135deg,#1677ff 0%,#722ed1 100%);display:flex;justify-content:space-between;align-items:center;flex-shrink:0;position:relative;z-index:5;padding-left:28px;';header.innerHTML='<span style="font-weight:600;color:white;font-size:15px;">💬 AI Data Assistant</span><span class="ai-close-btn" style="cursor:pointer;color:rgba(255,255,255,0.8);font-size:18px;width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:6px;transition:background 0.2s;">✕</span>';const iframeWrap=document.createElement('div');iframeWrap.style.cssText='flex:1;position:relative;overflow:hidden;';const iframe=document.createElement('iframe');iframe.src=AGENT_URL;iframe.style.cssText='width:100%;height:100%;border:none;';iframe.allow='clipboard-write';const dragMask=document.createElement('div');dragMask.style.cssText='position:absolute;top:0;left:0;width:100%;height:100%;background:transparent;z-index:10;display:none;';iframeWrap.appendChild(iframe);iframeWrap.appendChild(dragMask);chatWindow.appendChild(resizeHandle);chatWindow.appendChild(header);chatWindow.appendChild(iframeWrap);document.body.appendChild(btn);document.body.appendChild(chatWindow);btn.onclick=()=>{isOpen=!isOpen;chatWindow.style.display=isOpen?'flex':'none';};const closeBtn=header.querySelector('.ai-close-btn');closeBtn.onmouseenter=()=>closeBtn.style.background='rgba(255,255,255,0.2)';closeBtn.onmouseleave=()=>closeBtn.style.background='transparent';closeBtn.onclick=(e)=>{e.stopPropagation();isOpen=false;chatWindow.style.display='none';};btn.onmouseenter=()=>{btn.style.transform='scale(1.05)';btn.style.boxShadow='0 6px 20px rgba(22,119,255,0.5)';};btn.onmouseleave=()=>{btn.style.transform='scale(1)';btn.style.boxShadow='0 4px 16px rgba(22,119,255,0.4)';};resizeHandle.addEventListener('mousedown',(e)=>{e.preventDefault();e.stopPropagation();isResizing=true;startX=e.clientX;startY=e.clientY;startW=chatWindow.offsetWidth;startH=chatWindow.offsetHeight;dragMask.style.display='block';document.body.style.cursor='nesw-resize';document.body.style.userSelect='none';});document.addEventListener('mousemove',(e)=>{if(!isResizing)return;const dx=e.clientX-startX;const dy=e.clientY-startY;let newW=startW-dx;let newH=startH-dy;newW=Math.max(360,Math.min(newW,window.innerWidth*0.9));newH=Math.max(480,Math.min(newH,window.innerHeight*0.9));chatWindow.style.width=newW+'px';chatWindow.style.height=newH+'px';});document.addEventListener('mouseup',()=>{if(isResizing){isResizing=false;dragMask.style.display='none';document.body.style.cursor='';document.body.style.userSelect='';}});})();
Before opening the AI assistant, the interface looks like this:
After clicking the bookmark to open it, it looks like this:
Step 8: Test & Go Live
- Restart the local service and open the SmartBI page.
- Click the 'AI Data Assistant' in the bookmark bar, and a floating button will appear in the bottom right corner.
- Click to open it and start chatting. Ask things like 'What is the total sales amount?' or 'Which region sold the best?'. The AI will automatically call the tools to query the data.
- After local testing is fine, deploy online with one click:
edgeone makers deploy
- Wait 1 minute for deployment to complete. You'll get a public URL. Replace the local IP in the bookmark with the public URL, and the whole company can use it.
2. Pitfall Log (Don't Step on the Ones I Did)
1. Windows GBK Encoding Error
- Symptom: Error on service startup, UnicodeEncodeError
- Cause: Windows defaults to GBK encoding; emojis and Chinese output in the code cause errors.
- Solution: Execute
set PYTHONUTF8=1before starting.
2. Module Import Path Error
- Symptom: Startup reports 503, cannot import name 'TOOLS'
- Cause: The relative import path is wrong; EdgeOne's runtime directory structure differs from the local one.
- Solution: Place smartbi_tool.py in the same directory as index.py, and import using a single dot:
from .smartbi_tool import.
3. Dataset ID Pitfall
- Symptom: Query reports dataset does not exist.
- Cause: Initially thought all IDs needed a prefix 'I', but later found that enhanced dataset IDs don't. Copying directly from resource properties is the most accurate.
- Solution: Right-click on the SmartBI dataset -> Properties, copy the node ID. Do not add a prefix yourself.
4. Field Name Pitfall
- Symptom: API returns field does not exist.
- Cause: Thought field names were the same as in the SQL dataset, but they are actually the names in the measure fields, which default to having a
_msuffix. - Solution: Add the
_msuffix to all measure fields. This way, the agent won't report errors and will identify them accurately.
5. Metadata Interface 404
- Symptom: The field retrieval interface consistently returns 404.
- Cause: This interface is only for specific versions; ordinary enhanced datasets don't need it.
- Solution: Directly delete the get_dataset_schema tool. No need to retrieve fields; just query using Chinese field names.
6. iframe Blocked by X-Frame-Options
- Symptom: iframe shows connection refused.
- Cause: Vite does not allow iframe embedding by default.
- Solution: Configure X-Frame-Options and CSP in vite.config.ts to allow embedding from the SmartBI domain.
7. crypto.randomUUID Error in HTTP Environment
- Symptom: Error when opening the chat interface: crypto.randomUUID is not a function.
- Cause: The crypto API is only available in HTTPS environments, not in intranet HTTP environments.
- Solution: Add a polyfill in index.html. The code is provided above.
8. Tampermonkey Script Blocked by CSP
- Symptom: Tampermonkey script injection doesn't work; console reports CSP error.
- Cause: SmartBI has a strict Content Security Policy that blocks Tampermonkey scripts.
- Solution: Don't use Tampermonkey. Use the bookmarklet method for injection; it's simple, reliable, and won't be blocked.
9. CSS resize Not Working
- Symptom: Added resize:both, but mouse on the border has no effect.
- Cause: Cross-origin iframes intercept mouse events; CSS resize doesn't work on containers with an iframe.
- Solution: Implement dragging with JS. During a drag, add a transparent mask over the iframe to prevent event interception.
10. Tool Parameter Type Pitfall
- Symptom: Tool call error, additionalProperties not allowed.
- Cause: The OpenAI Agents SDK has poor support for complex types like list/dict.
- Solution: Use simple types for parameters. Pass multiple fields as a comma-separated string, not an array.
3. Future Optimization Plans
The tool is up and running, but it's currently just a minimum viable version. There's room for further optimization. What I can think of so far includes:
- Full Dynamic Dataset Support: Optimize the recursive logic of list_datasets to automatically identify all dozens of datasets. The AI would automatically match user questions to the corresponding dataset, eliminating hardcoding.
- Advanced Query Capabilities: Support for filter conditions, grouping and aggregation, time filtering, and year-over-year/month-over-month calculations to answer more complex business questions.
- Automatic Chart Generation: After querying data, automatically generate bar charts, line charts, and pie charts, eliminating the need to create reports manually.
- User Permission Passthrough: Obtain the identity of the currently logged-in SmartBI user and query data with corresponding permissions for data permission isolation.
- Formal Integration: Develop it as a SmartBI extension package that loads automatically upon login, removing the need to manually click a bookmark.
- Intelligent Q&A Optimization: Support for multi-turn conversations, context memory, and follow-up questions. For example, after asking about the best region, being able to ask 'Which product sold best in that region?' without repeating conditions.
4. Some Thoughts
EdgeOne Makers Has Really Lowered the Development Barrier
In the past, making an AI assistant like this would have required me to:
- Write a frontend chat interface (at least 1 day)
- Write backend APIs and handle SSE streaming output (half a day)
- Buy a server, set up the environment, and get an HTTPS domain (half a day)
- Handle cross-origin issues, deployment, and maintenance (half a day)
- Write tool logic and tune prompts (half a day)
Altogether, it would have taken at least 3 days, not counting various environmental issues.
But with EdgeOne Makers, the frontend chat interface, session memory, streaming output, tool-calling framework, deployment, and HTTPS domain are all done for you. I only needed to write the core SmartBI query tool and tune the prompt. It was done in one day, and the free tier is sufficient for a small team. It really frees developers from repetitive infrastructure work.
AI is Changing How We Work
Before, when building a feature, we'd spend 80% of our time on 'scaffolding': writing interfaces, doing APIs, deploying, and configuring environments. Only 20% of the time was spent on actually solving business problems. Now, with AI Agent frameworks + low-code platforms, 80% of the scaffolding is done for you. We only need to focus on that 20% of core business logic.
In the future, every system will have its own AI assistant. No need to learn complex operations or memorize function menus; natural language will be the interface. Business people can ask questions directly without waiting for data developers to schedule report creation. Data developers can also be freed from repetitive data retrieval tasks to do more valuable data construction work.
I used to think AI would replace programmers. Now I realize it's not replacement, but multiplication — a programmer who knows how to use AI tools can single-handedly match the output of a small team from before. For this BI assistant, I, a backend developer, didn't write a single line of frontend code and built it in one day. That was unthinkable before. Now, when business colleagues need simple data, they don't have to ping me on DingTalk to schedule it. They just open BI, click a bookmark, and ask, 'What is the total sales amount for fish products in East China in June?' The result comes out in seconds with automatic summaries. Yesterday, after an operations colleague used it, they chased me down asking how to do it, saying they wanted to set one up for their backend too 😂
If you also want to add an AI assistant to your company's system, definitely give EdgeOne Makers a try. You can build your own AI application at zero cost; the barrier is much lower than you think.
After all, for data folks, writing fewer repetitive SQL queries for data retrieval and leaving more time for slacking off is the real deal 😎 This article has laid out all the pitfalls I stepped on and the complete, runnable code. If you follow the steps, you'll definitely be able to install an AI assistant for your company's system too.
If you find this useful, don't forget to like 👍, bookmark ⭐, and forward. If you have any questions or encounter new pitfalls, leave a comment and I'll reply~ Also, everyone is welcome to try EdgeOne Makers. There are ready-made examples now; building your own little AI tool at zero cost is really sweet.
🎊 The end, thanks for reading this far~ 🎊
First published at: https://cloud.tencent.com/developer/article/2701802?shareByChannel=link Comments and forwards are welcome!