Trivial Proof-of-Concept Data Analysis Agent using Qwen3-1.7B
SLM
agentic
data analysis
logistics
in a previous blog post, I used the Anthropic Python SDK with Sonnet 4.6 to create a trivial proof-of-concept data analysis agent with custom tools. In this blog post, I am seeing if I can use Qwen3-1.7B to achieve the same result.
Author
Vishal Bakshi
Published
August 24, 2026
In a previous blog post and corresponding notebook, I showed an example of how I see LLMs as an interface. In the example, I used the Blue Book for Bulldozers Kaggle dataset as my data source and wrote a couple of functions that aggregate the data and render it in an HTML file. I gave Sonnet 4.6 those functions as tools plus instructions, using the Anthropic Python SDK, and it was able to generate the desired report given a user prompt.
In this blog post, I’m going to see if I can recreate that pipeline with the Qwen 3-1.7B open-source model and my own code interpreter (copied from Jeremy Howard’s Hacker’s Guide to LLMs repo).
bluebook-for-bulldozers.zip: Skipping, found more recently modified local copy (use --force to force download)
/tmp/ipykernel_813/2859010916.py:6: DtypeWarning: Columns (13,39,40,41) have mixed types. Specify dtype option on import or set low_memory=False.
df = pd.read_csv("/content/bluebook-for-bulldozers/TrainAndValid.csv")
def make_prompt(function_signature, user_request, data_source=None, data_dict=False, function1_output=None): prompt =f"""You are given the following function and additional context.Based on the user's request, output a python dict of the function name and arguments.Output only a valid dict, nothing else.Do not include function results in the dict.FUNCTION:{function_signature}"""if data_source: prompt +=f"""DATA SOURCE: "{data_source}" """if data_dict: prompt +=f"""DATA DICTIONARY:salesdata.csv contains the following relevant columns:- state (str): the state where the sale took place"""if function1_output: prompt +=f"""The following data{function1_output}should be an argument for the function, structured as{{"data": {function1_output}}}""" prompt +=f"""USER REQUEST:{user_request}OUTPUT FORMAT:{{"function": "<name>", "arguments": {{<args>}}, ...}}You are given the above function and additional context.Based on the user's request, output a python dict of the function name and arguments.Output only a valid dict, nothing else.Do not include function results in the dict output. """return prompt
I will provide the function signature for two functions separately, as I want Qwen to use each one sequentially.
function1_signature ="""aggregated_filtered_saleprice(path_to_csv: str, groupby_fields: list[str], filter_column: str, filter_values: list[str]) Aggregate and filter the sales data to calculate the mean sale price."""function2_signature ="""generate_report(data: dict) The data argument should be the entire dictionary passed as a single argument."""data_source ="/content/salesdata.csv"user_request ="Using the provided tools and data source, generate an HTML report that shows the mean sale price in Alabama and Missouri."
You are given the following function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict.
FUNCTION:
aggregated_filtered_saleprice(path_to_csv: str, groupby_fields: list[str], filter_column: str, filter_values: list[str])
Aggregate and filter the sales data to calculate the mean sale price.
DATA SOURCE: "/content/salesdata.csv"
DATA DICTIONARY:
salesdata.csv contains the following relevant columns:
- state (str): the state where the sale took place
USER REQUEST:
Using the provided tools and data source, generate an HTML report that shows the mean sale price in Alabama and Missouri.
OUTPUT FORMAT:
{"function": "<name>", "arguments": {<args>}, ...}
You are given the above function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict output.
You are given the following function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict.
FUNCTION:
generate_report(data: dict)
The data argument should be the entire dictionary passed as a single argument.
The following data
{'blah': 'boop'}
should be an argument for the function, structured as
{"data": {'blah': 'boop'}}
USER REQUEST:
Using the provided tools and data source, generate an HTML report that shows the mean sale price in Alabama and Missouri.
OUTPUT FORMAT:
{"function": "<name>", "arguments": {<args>}, ...}
You are given the above function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict output.
I was surprised. I did not expect the size of this model to be able to handle this. And that’s without thinking! This goes to show how far small models have advanced! Or maybe it just shows how out of touch I am with small models of this size (I spent most of my time on tiny models last year).
Let’s create a function that will execute a Python function given JSON arguments. Then I’ll define my aggregate filtered sale price function and call it with the parsed content.
def call_func(name, arguments): f =globals()[name]return f(**json.loads(arguments) ifisinstance(arguments, str) else arguments)
def aggregated_filtered_saleprice(path_to_csv, groupby_fields, filter_column, filter_values):""" Aggregate and filter the sales data to calculate the mean sale price. inputs: path_to_csv: str groupby_fields: list of str filter_column: str filter_values: list of str output: json: str """ df = pd.read_csv(path_to_csv) data = df.groupby(groupby_fields).agg({"SalePrice": "mean"}).query(f"`{filter_column}` in @filter_values")return data.to_dict()
You are given the following function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict.
FUNCTION:
generate_report(data: dict)
The data argument should be the entire dictionary passed as a single argument.
The following data
{'SalePrice': {'Alabama': 37775.08474576271, 'Missouri': 27467.972350230415}}
should be an argument for the function, structured as
{"data": {'SalePrice': {'Alabama': 37775.08474576271, 'Missouri': 27467.972350230415}}}
USER REQUEST:
Using the provided tools and data source, generate an HTML report that shows the mean sale price in Alabama and Missouri.
OUTPUT FORMAT:
{"function": "<name>", "arguments": {<args>}, ...}
You are given the above function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict output.
def generate_report(data):""" Generate an HTML report from dict. inputs: data: dict output: None """ html =f"<h1>Data Report</h1><br>{data}"withopen("/content/report.html", "w") as f: f.write(html)print("HTML report generated")
user_request ="I need to know what the mean sale price was in the two states of Alabama and Missouri."
data_analysis_agent(user_request, data_source)
You are given the following function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict.
FUNCTION:
aggregated_filtered_saleprice(path_to_csv: str, groupby_fields: list[str], filter_column: str, filter_values: list[str])
Aggregate and filter the sales data to calculate the mean sale price.
DATA SOURCE: "/content/salesdata.csv"
DATA DICTIONARY:
salesdata.csv contains the following relevant columns:
- state (str): the state where the sale took place
USER REQUEST:
I need to know what the mean sale price was in the two states of Alabama and Missouri.
OUTPUT FORMAT:
{"function": "<name>", "arguments": {<args>}, ...}
You are given the above function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict output.
You are given the following function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict.
FUNCTION:
generate_report(data: dict)
The data argument should be the entire dictionary passed as a single argument.
The following data
{'SalePrice': {'Alabama': 37775.08474576271, 'Missouri': 27467.972350230415}}
should be an argument for the function, structured as
{"data": {'SalePrice': {'Alabama': 37775.08474576271, 'Missouri': 27467.972350230415}}}
USER REQUEST:
I need to know what the mean sale price was in the two states of Alabama and Missouri.
OUTPUT FORMAT:
{"function": "<name>", "arguments": {<args>}, ...}
You are given the above function and additional context.
Based on the user's request, output a python dict of the function name and arguments.
Output only a valid dict, nothing else.
Do not include function results in the dict output.
HTML report generated
'Done'
Cool! It wasn’t very challenging because my user request was very similar, but as a trivial example, I’m satisfied.
Post-Mortem
What did I learn?
I need more practice with these medium-sized small models because they are capable of a lot more than I expected!
Custom tool-calling capability requires more elbow grease than I expected. I went through multiple iterations of the prompt before call_func worked as expected.
If you have relatively stable executable scripts, such that you create deterministic prompts in your chain of tool-calls, Qwen3-1.7B might be worth giving a shot!