{"id":17767,"date":"2025-08-19T15:19:06","date_gmt":"2025-08-19T12:19:06","guid":{"rendered":"https:\/\/spatialworld.fi\/?page_id=17767"},"modified":"2025-11-06T10:05:07","modified_gmt":"2025-11-06T08:05:07","slug":"fme-blog-duckdb-llm-reporting","status":"publish","type":"page","link":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/","title":{"rendered":"fme-duckdb-llm-reporting"},"content":{"rendered":"[vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>Answer any question on any dataset using FME, DuckDB and OpenAI.<\/h1>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][image_with_animation image_url=&#8221;17854&#8243; image_size=&#8221;full&#8221; max_width=&#8221;100%&#8221; max_width_mobile=&#8221;default&#8221; animation_type=&#8221;entrance&#8221; animation=&#8221;None&#8221; animation_movement_type=&#8221;transform_y&#8221; hover_animation=&#8221;none&#8221; alignment=&#8221;center&#8221; border_radius=&#8221;none&#8221; box_shadow=&#8221;none&#8221; image_loading=&#8221;default&#8221;][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1><span lang=\"en-FI\">Introduction<\/span><\/h1>\n<p><strong>Goal: <\/strong>Show, step-by-step, how to leverage FME\u2019s flexibility and orchestration, DuckDB, and LLMs to answer questions on a dataset.<\/p>\n<p><strong>Approach:<\/strong> We combine FME for robust ingestion, DuckDB for fast SQL+metadata, and three LLMs roles (<strong>Planner<\/strong>, <strong>SQL Generator,<\/strong> and <strong>Analyst<\/strong>) to produce queries and render an HTML report.<\/p>\n<p><strong>What you\u2019ll get:<\/strong> A reusable FME workspace that converts any tabular input to Parquet, extracts schema\/summary\/sample, plans questions, runs SQL, and renders a markdown-to-HTML analysis.<\/p>\n<p><strong>Dataset:<\/strong><\/p>\n<p><a href=\"https:\/\/hri.fi\/data\/fi\/dataset\/helsingin-pyorailijamaarat\">An Excel file (Finnish headers) with daily cyclist counts per sensor location in Helsinki.<\/a><\/p>\n<p><strong>Example question:<\/strong><\/p>\n<p>Where are the places with more cyclists? When is it happening?<\/p>\n<p><strong>Template:<\/strong><\/p>\n<p><a href=\"https:\/\/hub.safe.com\/publishers\/antoine\/templates\/llm_sql_report_demo\">https:\/\/hub.safe.com\/publishers\/antoine\/templates\/llm_sql_report_demo<\/a><\/p>\n<p><strong>The main steps are:<\/strong><\/p>\n<ol>\n<li>Convert any file to a temp Parquet with <strong>FME<\/strong><\/li>\n<li>Execute simple analysis on the Parquet file with <strong>DuckDB<\/strong> to get metadata<\/li>\n<li>Ask the <strong>LLM<\/strong>, fed with metadata, to produce formalized questions and SQL queries able to answer the question<\/li>\n<li>Ask another, lighter, <strong>LLM<\/strong> to generate SQL queries based on the simpler\/more formal questions of the first one.<\/li>\n<li>Run all the SQL queries with <strong>DuckDB<\/strong> on the complete temporary table<\/li>\n<li><strong>LLM<\/strong> analyses the SQL answers in regards with the original task.<\/li>\n<li><strong>FME<\/strong> and <strong>LLM<\/strong> together produce an HTML report, answering the global questions<\/li>\n<\/ol>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1><span lang=\"en-FI\">1. Convert any file to Parquet<\/span><\/h1>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][image_with_animation image_url=&#8221;17855&#8243; image_size=&#8221;full&#8221; max_width=&#8221;100%&#8221; max_width_mobile=&#8221;default&#8221; animation_type=&#8221;entrance&#8221; animation=&#8221;None&#8221; animation_movement_type=&#8221;transform_y&#8221; hover_animation=&#8221;none&#8221; alignment=&#8221;center&#8221; border_radius=&#8221;none&#8221; box_shadow=&#8221;none&#8221; image_loading=&#8221;default&#8221;][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]FME is a very powerful tool able to digest hundreds of formats into its own internal format. Our input here is a (peculiar&#8230;) Excel file in Finnish. We will dynamically convert it to Parquet:<\/p>\n<ul>\n<li>BulkAttributeRenamer allows us to replace all strange characters which could have slipped into our attribute names into \u201c_\u201d: [^\\p{L}\\p{N}_]<\/li>\n<li>SchemaScanner allows us to consolidate this updated schema<\/li>\n<li>FeatureWriter writes the data to Parquet, fed with both data and schema<\/li>\n<\/ul>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][image_with_animation image_url=&#8221;17856&#8243; image_size=&#8221;full&#8221; max_width=&#8221;100%&#8221; max_width_mobile=&#8221;default&#8221; animation_type=&#8221;entrance&#8221; animation=&#8221;None&#8221; animation_movement_type=&#8221;transform_y&#8221; hover_animation=&#8221;none&#8221; alignment=&#8221;&#8221; border_radius=&#8221;none&#8221; box_shadow=&#8221;none&#8221; image_loading=&#8221;default&#8221;][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>2. Execute simple analysis<\/h1>\n<p>As we cannot feed the whole table to the LLM, we will feed it with metadata<\/p>\n<ul>\n<li>Table schema<\/li>\n<li>Statistical summary<\/li>\n<li>Sample<\/li>\n<\/ul>\n<h2>2.1 Produce schema<\/h2>\n<ul>\n<li><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17857\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png\" alt=\"\" width=\"217\" height=\"300\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png 217w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004.png 234w\" sizes=\"auto, (max-width: 217px) 100vw, 217px\" \/><\/a>DatabaseQuerier :<\/li>\n<\/ul>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>FME_SQL_DELIMITER |<br \/>\nCREATE TABLE test_table AS<br \/>\nSELECT * FROMread_parquet(&#8216;@Value(_dataset)\/test_table.parquet&#8217;) LIMIT 10;|<br \/>\nEXPORT DATABASE &#8216;$(tempFolder)&#8217;;|<br \/>\nDROP TABLE test_table;|<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>We want the schema of the table to be sent in an \u201cSQL\u201d format, to the LLM. DuckDB, called in FME, allows us to do it with this set of queries:<\/p>\n<p>&nbsp;<\/p>\n<p>This will generate a series of small files regarding our table, one, called \u201cschema.sql\u201d containing the CREATE TABLE.<\/p>\n<ul>\n<li>AttributeFileReader allows to read a file into an attribute, here the \u201cschema.sql\u201d fil<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image006.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17859\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image006-300x150.png\" alt=\"\" width=\"300\" height=\"150\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image006-300x150.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image006.png 302w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h2>2.2 Produce Summary<\/h2>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image007.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-17860 aligncenter\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image007-300x75.png\" alt=\"\" width=\"300\" height=\"75\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image007-300x75.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image007-600x151.png 600w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image007.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>DuckDB offers a Summarize statement (<a href=\"https:\/\/duckdb.org\/docs\/stable\/sql\/statements\/summarize\">https:\/\/DuckDB.org\/docs\/stable\/sql\/statements\/summarize<\/a>). This gives a good idea about how each field is populated and is very important to know how to query the table. Here again, we read the result back to an attribute.<\/p>\n<p>&nbsp;<\/p>\n<h2>2.3 Produce a Sample<\/h2>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image008.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-17861 aligncenter\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image008-300x43.png\" alt=\"\" width=\"300\" height=\"43\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image008-300x43.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image008.png 601w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<ul>\n<li>Select * LIMIT 3 on the table<\/li>\n<li>ListBuilder to get only one feature<\/li>\n<li>AttributeJSONPacker to have it as one attribute<\/li>\n<\/ul>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>3. Call the LLM to generate questions and SQL<\/h1>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image009.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17862\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image009-300x149.png\" alt=\"\" width=\"300\" height=\"149\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image009-300x149.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image009-600x299.png 600w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image009.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Here is a bit more of Json and trial\/error part. We need to build a set of instructions, combining our new information with and our question so that the model answer in the expected way.<\/p>\n<p>Depending on your use case and model, you might need to a different structure.<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image010.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17863\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image010-300x68.png\" alt=\"\" width=\"300\" height=\"68\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image010-300x68.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image010.png 445w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<ul>\n<li>Task is the main question, straight from the user<\/li>\n<li>Format is the definition of the structured output we want. As we want the process to work on any question, the answer must always follow a defined structure, so that we can continue the process.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image011.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17864\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image011-300x117.png\" alt=\"\" width=\"300\" height=\"117\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image011-300x117.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image011.png 615w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<ul>\n<li>User prompt combines task, example of answer etc&#8230;<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image012.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17865\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image012-300x54.png\" alt=\"\" width=\"300\" height=\"54\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image012-300x54.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image012-600x108.png 600w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image012.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>System prompt sets the rules<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image013.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17866\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image013-300x105.png\" alt=\"\" width=\"300\" height=\"105\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image013-300x105.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image013.png 560w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>With these prompts we get a Json output from where we can export formalized questions and their SQL. The speed and quality depend a lot on your model choice<\/p>\n<p>&nbsp;<\/p>\n<p>In our case:<\/p>\n<ul>\n<li>the task is vague: where are the places with more cyclists? When is it happening?<\/li>\n<li>The table is a \u201cnot so well designed\u201d Excel in Finnish<\/li>\n<li>The answer is:<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image014.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17867\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image014-300x34.png\" alt=\"\" width=\"300\" height=\"34\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image014-300x34.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image014.png 601w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>The first query is trying to give a complex question\/query to answer directly the question. The secondary questions\/SQL queries are simpler ones, less likely to fail. All of them will later be sent to another LLM, faster and cheaper, to get again new queries. Depending on your mode, task and dataset, you might need more chances to get valid and useful ones.<\/p>\n[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>4. Produce a new set of SQL queries based on the questions<\/h1>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image015.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17868\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image015.png\" alt=\"\" width=\"280\" height=\"238\" \/><\/a><\/p>\n<p>As our first LLM answer might contain mistakes, we will ask another one to implement all the previous questions through SQL. This gives room for error and a bit more variety at a low cost, as we are picking a cheaper\/faster model for this. There is no need for it to understand the big task as it is answering the questions reframed by the first model.<\/p>\n<p>The steps are the same:<\/p>\n<ul>\n<li>Prompt preparation<a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image016.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17869\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image016-300x65.png\" alt=\"\" width=\"300\" height=\"65\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image016-300x65.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image016.png 518w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ul>\n<ul>\n<li>API call<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image017.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17870\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image017-300x215.png\" alt=\"\" width=\"300\" height=\"215\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image017-300x215.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image017.png 460w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<ul>\n<li>JSONFlattener to come back to classical FME attribute<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image018.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17871\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image018-300x46.png\" alt=\"\" width=\"300\" height=\"46\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image018-300x46.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image018.png 601w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>As you can read, the prompt and the output format are simpler. We only require an \u201csql\u201d element.<\/p>\n<p>&nbsp;<\/p>\n<p>We now have a set of 8 queries: 4 from the planner and 4 from the secondary call.<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image019.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17872\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image019-300x77.png\" alt=\"\" width=\"300\" height=\"77\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image019-300x77.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image019.png 601w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>5. Run the SQL queries<\/h1>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image020.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17873\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image020-300x280.png\" alt=\"\" width=\"300\" height=\"280\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image020-300x280.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image020.png 586w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>As an SQL query, in FME return n objects with an unknown schema, we chose to use the COPY statement. We could also have used the ListBuilder + AttributeJSONPacker but the resulting Json might be a bit further than the original answer.<\/p>\n<p>This implies that we remove the ending \u201c;\u201d from the queries with StringReplacer.<\/p>\n<p>As \u201cCopy\u201d supports only Select statement, we put the other queries into a SELECT one<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image021.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17874\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image021-300x100.png\" alt=\"\" width=\"300\" height=\"100\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image021-300x100.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image021.png 392w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>For SELECT statements, it is simpler, we just added \u201cLIMIT 30\u201d at the end of the queries to avoid big output files:<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image022.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17875\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image022-300x98.png\" alt=\"\" width=\"300\" height=\"98\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image022-300x98.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image022.png 383w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once again, the output file is then read to an attribute.<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image023.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17876\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image023-300x72.png\" alt=\"\" width=\"300\" height=\"72\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image023-300x72.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image023-600x144.png 600w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image023.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>6. LLM analysis and markdown report generation<\/h1>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image024.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17877\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image024-300x153.png\" alt=\"\" width=\"300\" height=\"153\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image024-300x153.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image024-600x308.png 600w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image024.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once we have collected all this information, FME shines in restructuring it to prepare for the LLM analysis. A combo of text and Json transformer can make any kind of prompt.<\/p>\n<ul>\n<li>System prompt:<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image025.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17878\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image025-300x154.png\" alt=\"\" width=\"300\" height=\"154\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image025-300x154.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image025.png 437w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>As you can see, nothing is specific, just rules. We chose Markdown as it is very light in terms of token but good as expressing a structure. Nothing prevents to summarize, translate, or make the report prettier later with cheaper models.<\/p>\n<ul>\n<li>User prompt:<\/li>\n<\/ul>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image026.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17879\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image026-300x188.png\" alt=\"\" width=\"300\" height=\"188\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image026-300x188.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image026.png 433w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>This prompt tries to aggregate all relevant information we collected and gives a \u201cstructure\u201d to the analysis.<\/p>\n<p>Body:<a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image027.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17880\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image027-300x285.png\" alt=\"\" width=\"300\" height=\"285\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image027-300x285.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image027.png 329w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>The format is specified, as always to allow an easy integration with the rest of the process. We chose a smarter model as there is a lot of info to articulate while keeping in mind the original task. Actually, gpt5 is even better but much more expensive.[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<h1>7. Report to HTML<\/h1>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image028.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17881\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image028-300x116.png\" alt=\"\" width=\"300\" height=\"116\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image028-300x116.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image028.png 533w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Once we got our Markdown report, it is very easy to translate it into whatever output you want. We chose to put it into an HTML file.<\/p>\n<p>For this we have an HTML attribute with a placeholder for the markdown element, we just put our report there.<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image029.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-17882\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image029.png\" alt=\"\" width=\"271\" height=\"241\" \/><\/a><\/p>\n<p>Once this text is ready, an HTML writer places it wherever needed.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image030.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-17883\" src=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image030-300x227.png\" alt=\"\" width=\"300\" height=\"227\" srcset=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image030-300x227.png 300w, https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image030.png 602w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>[\/vc_column_text][\/vc_column][\/vc_row][vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221; column_border_radius=&#8221;none&#8221; column_link_target=&#8221;_self&#8221; column_position=&#8221;default&#8221; gradient_direction=&#8221;left_to_right&#8221; overlay_strength=&#8221;0.3&#8243; width=&#8221;1\/1&#8243; tablet_width_inherit=&#8221;default&#8221; animation_type=&#8221;default&#8221; bg_image_animation=&#8221;none&#8221; border_type=&#8221;simple&#8221; column_border_width=&#8221;none&#8221; column_border_style=&#8221;solid&#8221;][vc_column_text css=&#8221;&#8221; text_direction=&#8221;default&#8221;]\n<p id=\"ember800\" class=\"ember-view reader-text-block__paragraph\">Congratulations! The report is pretty neat, the parts about limitations and next steps are important as they can hint you about 2 things:<\/p>\n<ul>\n<li>Did the model go wild and invent things<\/li>\n<li>Could I ask for a second round, with better questions, based on this output (agentic behavior).<\/li>\n<\/ul>\n<h1 id=\"ember802\" class=\"ember-view reader-text-block__heading-2\">Conclusion<\/h1>\n<p id=\"ember803\" class=\"ember-view reader-text-block__paragraph\">By separating <strong>ingestion<\/strong>, <strong>profiling<\/strong>, <strong>planning<\/strong>, <strong>querying<\/strong>, <strong>analysis<\/strong>, and <strong>reporting<\/strong>, we turned a messy Excel file with Finnish headers into clear answers about Helsinki\u2019s cycling patterns, without hand-crafting every SQL statement. FME handled the orchestration and format wrangling, DuckDB provided fast, local SQL over Parquet, and three focused LLM roles (Planner \u2192 SQL Generator \u2192 Analyst) kept the workflow reliable and cost-aware.<\/p>\n<p id=\"ember804\" class=\"ember-view reader-text-block__paragraph\">The result is a reusable pipeline you can point at almost any dataset to go from <em>question<\/em> \u2192 <em>queries<\/em> \u2192 <em>insightful HTML report<\/em>.<\/p>\n<p id=\"ember805\" class=\"ember-view reader-text-block__paragraph\">Just as important as the outcome is the <strong>discipline<\/strong> behind it: only small, meaningful slices of data (schema, summary stats, sample rows) went to the models; we enforced guardrails around SQL execution (COPY (SELECT \u2026), semicolon stripping, result caps); and we made the analyst step reason over named result sets instead of raw tables. This keeps the LLMs in their lane and the data work where it belongs.<\/p>\n<h3 id=\"ember806\" class=\"ember-view reader-text-block__heading-3\">What you now have<\/h3>\n<ul>\n<li>A <strong>template workspace<\/strong> that standardizes any table to Parquet and profiles it for downstream intelligence.<\/li>\n<li>A <strong>repeatable prompting pattern<\/strong>: Planner for structure, lighter model for SQL, heavier model for synthesis.<\/li>\n<li>A <strong>reporting path<\/strong> that turns Markdown into shareable HTML with minimal glue.<\/li>\n<\/ul>\n<h3 id=\"ember808\" class=\"ember-view reader-text-block__heading-3\">Where to take it next<\/h3>\n<ul>\n<li>Define each main step as an independent process to build flexible Automations in FME Flow.<\/li>\n<li>Complete the report with trustable &#8220;raw&#8221; metadata and summaries from profiling tools like <a class=\"yRgCVsjrzAHkdCEjqvAcmnsmCUhbwIZbY \" tabindex=\"0\" href=\"https:\/\/hub.safe.com\/publishers\/antoine\/transformers\/pandasprofiling_report_beta\" target=\"_self\" data-test-app-aware-link=\"\">Pandas profiling.<\/a><\/li>\n<\/ul>\n<h3 id=\"ember810\" class=\"ember-view reader-text-block__heading-3\">Final thought<\/h3>\n<p id=\"ember811\" class=\"ember-view reader-text-block__paragraph\">The power here isn\u2019t just that LLMs can write SQL, it\u2019s that, with the right <strong>boundaries and roles<\/strong>, they help you ask better questions and automate the boring parts. Keep the contracts between steps tight, measure what matters (quality, cost, latency), and this pattern will scale from a single Helsinki bike counter to your entire data estate.<\/p>\n[\/vc_column_text][\/vc_column][\/vc_row]","protected":false},"excerpt":{"rendered":"<p>[vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221;&#8230;<\/p>\n","protected":false},"author":6,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-17767","page","type-page","status-publish"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>fme-duckdb-llm-reporting - Spatialworld Oy<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/\" \/>\n<meta property=\"og:locale\" content=\"sv_SE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"fme-duckdb-llm-reporting - Spatialworld Oy\" \/>\n<meta property=\"og:description\" content=\"[vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221;...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/\" \/>\n<meta property=\"og:site_name\" content=\"Spatialworld Oy\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-06T08:05:07+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png\" \/>\n<meta name=\"twitter:label1\" content=\"Ber\u00e4knad l\u00e4stid\" \/>\n\t<meta name=\"twitter:data1\" content=\"12 minuter\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/\",\"url\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/\",\"name\":\"fme-duckdb-llm-reporting - Spatialworld Oy\",\"isPartOf\":{\"@id\":\"https:\/\/spatialworld.fi\/sv\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/spatialworld.fi\/fme-blog-duckdb-llm-reporting\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png\",\"datePublished\":\"2025-08-19T12:19:06+00:00\",\"dateModified\":\"2025-11-06T08:05:07+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#breadcrumb\"},\"inLanguage\":\"sv-SE\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[[\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/\"]]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"sv-SE\",\"@id\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#primaryimage\",\"url\":\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png\",\"contentUrl\":\"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/spatialworld.fi\/sv\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"fme-duckdb-llm-reporting\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/spatialworld.fi\/sv\/#website\",\"url\":\"https:\/\/spatialworld.fi\/sv\/\",\"name\":\"Spatialworld Oy\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/spatialworld.fi\/sv\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"sv-SE\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"fme-duckdb-llm-reporting - Spatialworld Oy","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/","og_locale":"sv_SE","og_type":"article","og_title":"fme-duckdb-llm-reporting - Spatialworld Oy","og_description":"[vc_row type=&#8221;in_container&#8221; full_screen_row_position=&#8221;middle&#8221; column_margin=&#8221;default&#8221; column_direction=&#8221;default&#8221; column_direction_tablet=&#8221;default&#8221; column_direction_phone=&#8221;default&#8221; scene_position=&#8221;center&#8221; text_color=&#8221;dark&#8221; text_align=&#8221;left&#8221; row_border_radius=&#8221;none&#8221; row_border_radius_applies=&#8221;bg&#8221; overflow=&#8221;visible&#8221; overlay_strength=&#8221;0.3&#8243; gradient_direction=&#8221;left_to_right&#8221; shape_divider_position=&#8221;bottom&#8221; bg_image_animation=&#8221;none&#8221;][vc_column column_padding=&#8221;no-extra-padding&#8221; column_padding_tablet=&#8221;inherit&#8221; column_padding_phone=&#8221;inherit&#8221; column_padding_position=&#8221;all&#8221; column_element_direction_desktop=&#8221;default&#8221; column_element_spacing=&#8221;default&#8221; desktop_text_alignment=&#8221;default&#8221; tablet_text_alignment=&#8221;default&#8221; phone_text_alignment=&#8221;default&#8221; background_color_opacity=&#8221;1&#8243; background_hover_color_opacity=&#8221;1&#8243; column_backdrop_filter=&#8221;none&#8221; column_shadow=&#8221;none&#8221;...","og_url":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/","og_site_name":"Spatialworld Oy","article_modified_time":"2025-11-06T08:05:07+00:00","og_image":[{"url":"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png","type":"","width":"","height":""}],"twitter_misc":{"Ber\u00e4knad l\u00e4stid":"12 minuter"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/","url":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/","name":"fme-duckdb-llm-reporting - Spatialworld Oy","isPartOf":{"@id":"https:\/\/spatialworld.fi\/sv\/#website"},"primaryImageOfPage":{"@id":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#primaryimage"},"image":{"@id":"https:\/\/spatialworld.fi\/fme-blog-duckdb-llm-reporting\/#primaryimage"},"thumbnailUrl":"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png","datePublished":"2025-08-19T12:19:06+00:00","dateModified":"2025-11-06T08:05:07+00:00","breadcrumb":{"@id":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#breadcrumb"},"inLanguage":"sv-SE","potentialAction":[{"@type":"ReadAction","target":[["https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/"]]}]},{"@type":"ImageObject","inLanguage":"sv-SE","@id":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#primaryimage","url":"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png","contentUrl":"https:\/\/spatialworld.fi\/wp-content\/uploads\/2025\/11\/image004-217x300.png"},{"@type":"BreadcrumbList","@id":"https:\/\/spatialworld.fi\/sv\/fme-blog-duckdb-llm-reporting\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/spatialworld.fi\/sv\/"},{"@type":"ListItem","position":2,"name":"fme-duckdb-llm-reporting"}]},{"@type":"WebSite","@id":"https:\/\/spatialworld.fi\/sv\/#website","url":"https:\/\/spatialworld.fi\/sv\/","name":"Spatialworld Oy","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/spatialworld.fi\/sv\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"sv-SE"}]}},"_links":{"self":[{"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/pages\/17767","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/comments?post=17767"}],"version-history":[{"count":21,"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/pages\/17767\/revisions"}],"predecessor-version":[{"id":17949,"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/pages\/17767\/revisions\/17949"}],"wp:attachment":[{"href":"https:\/\/spatialworld.fi\/sv\/wp-json\/wp\/v2\/media?parent=17767"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}