品經(jīng)理從原型到簡(jiǎn)歷的完整作品集實(shí)戰(zhàn))
聊聊最近被不少 AI 產(chǎn)品經(jīng)理同行問(wèn)爆的一個(gè)組合Vibe Coding ChatBI。圈子里好像一夜之間都在聊“用嘴寫(xiě)代碼”“讓 AI 自己搭數(shù)據(jù)分析系統(tǒng)”。很多朋友想把這套東西做成作品集寫(xiě)進(jìn)簡(jiǎn)歷但又不知道從哪兒開(kāi)始下手更不知道簡(jiǎn)歷上到底該怎么寫(xiě)才不虛。先說(shuō)結(jié)論Vibe Coding 不是歪門(mén)邪道也不是“偷懶不寫(xiě)代碼”它是 AI 時(shí)代產(chǎn)品經(jīng)理快速驗(yàn)證想法的一種新的工作方式。而 ChatBI對(duì)話(huà)式數(shù)據(jù)智能是目前最適合拿來(lái)當(dāng)作品集落地場(chǎng)景的 AI 應(yīng)用之一——需求清晰、價(jià)值明顯、技術(shù)鏈路完整面試官一看就懂問(wèn)起來(lái)也有話(huà)聊。這篇文章我會(huì)從一個(gè) AI 產(chǎn)品經(jīng)理的實(shí)際視角出發(fā)拆解三件事Vibe Coding 到底是什么、怎么用它把一個(gè) ChatBI 從想法變成能跑的原型以及最后怎么把這個(gè)作品集專(zhuān)業(yè)地寫(xiě)進(jìn)簡(jiǎn)歷里。全程給可復(fù)用的提示詞、代碼思路和簡(jiǎn)歷模板不是那種只講概念的空文章。1. 背景與核心概念1.1 為什么 AI 產(chǎn)品經(jīng)理需要“作品集”傳統(tǒng)產(chǎn)品經(jīng)理找工作靠的是 PRD、原型圖、數(shù)據(jù)報(bào)告和講項(xiàng)目故事的能力。但 AI 產(chǎn)品經(jīng)理面臨的情況不太一樣面試官尤其是一線技術(shù)負(fù)責(zé)人很難通過(guò)文檔判斷你是否真的理解 AI 能力邊界。你說(shuō)你設(shè)計(jì)過(guò)一個(gè)智能客服問(wèn)你 Prompt 怎么調(diào)優(yōu)、模型幻覺(jué)怎么處理、召回率怎么測(cè)答不上來(lái)就露餡了。作品集的核心作用是證明“我不光會(huì)畫(huà)圖寫(xiě)文檔我真的動(dòng)手把一個(gè) AI 應(yīng)用從概念推到了可用狀態(tài)”。而 AI 產(chǎn)品經(jīng)理的作品集和程序員的作品集有一個(gè)本質(zhì)區(qū)別重點(diǎn)不是代碼寫(xiě)得多漂亮而是你如何定義問(wèn)題、拆解功能、評(píng)估效果、迭代優(yōu)化。所以作品集不要求你有高級(jí)工程師的編碼水平但要求你能用最低成本把想法落地成可體驗(yàn)、可演示、可分析的產(chǎn)品。1.2 Vibe Coding 是什么解決什么問(wèn)題Vibe Coding 這個(gè)詞最早流行起來(lái)源于大家發(fā)現(xiàn)用自然語(yǔ)言給 AI 編程助手比如 Cursor、Claude、GPT 的 Artifacts、DeepSeek、通義靈碼等下達(dá)指令已經(jīng)能完成相當(dāng)一部分實(shí)際開(kāi)發(fā)工作。它不強(qiáng)調(diào)手寫(xiě)每一行代碼而是強(qiáng)調(diào)用清晰的意圖描述驅(qū)動(dòng) AI 生成代碼自己負(fù)責(zé)判斷、組合、調(diào)試和驗(yàn)證。對(duì) AI 產(chǎn)品經(jīng)理來(lái)說(shuō)Vibe Coding 的意義不是替代工程師而是快速做原型把想法直接跟 AI 說(shuō)幾分鐘拿到一個(gè)可點(diǎn)擊、可交互、可演示的頁(yè)面。驗(yàn)證技術(shù)可行性不確定某個(gè)功能能不能做直接讓 AI 寫(xiě)一版試試比爭(zhēng)論半天都有效。降低溝通成本你手上有個(gè)能跑的 Demo和技術(shù)團(tuán)隊(duì)溝通需求時(shí)大家對(duì)著真實(shí)系統(tǒng)討論而不是對(duì)著文字想象。補(bǔ)齊產(chǎn)品 Sense 到技術(shù)理解之間的空檔通過(guò)親手調(diào)試 Prompt、修改參數(shù)、觀察錯(cuò)誤日志你能真正理解模型的能力邊界。有人可能會(huì)擔(dān)心這是不是在鼓勵(lì)產(chǎn)品經(jīng)理?yè)尮こ處煹幕钗覀€(gè)人的觀點(diǎn)是Vibe Coding 產(chǎn)出的是“原型”“樣板”和“作品集”不是高并發(fā)高可用的商業(yè)系統(tǒng)。你的目標(biāo)是用它來(lái)驗(yàn)證和表達(dá)而不是用它替代專(zhuān)業(yè)研發(fā)流程。1.3 ChatBI 是什么為什么適合做成作品集ChatBI 是 Chat Business Intelligence 的縮寫(xiě)指通過(guò)自然語(yǔ)言對(duì)話(huà)的方式來(lái)查詢(xún)、分析和理解業(yè)務(wù)數(shù)據(jù)。你可以把它理解成一個(gè)“能聊天”的數(shù)據(jù)分析助手。傳統(tǒng) BI 工具要求用戶(hù)會(huì)拖拽報(bào)表、懂維度指標(biāo)、能自己寫(xiě) SQLChatBI 做的事情是讓用戶(hù)直接問(wèn)“上個(gè)月華東區(qū)域的銷(xiāo)售額環(huán)比增長(zhǎng)了多少哪個(gè)品類(lèi)貢獻(xiàn)最大”系統(tǒng)自動(dòng)理解問(wèn)題生成查詢(xún)邏輯返回結(jié)果甚至自動(dòng)生成圖表。ChatBI 作為 AI 產(chǎn)品經(jīng)理的作品集有幾個(gè)天然優(yōu)勢(shì)需求場(chǎng)景普及幾乎每個(gè)公司都有數(shù)據(jù)分析需求面試官完全能理解這個(gè)產(chǎn)品解決什么問(wèn)題。技術(shù)鏈路完整涉及 NL2SQL、意圖識(shí)別、Prompt 工程、可視化、數(shù)據(jù)權(quán)限、效果評(píng)估這些都是 AI 產(chǎn)品經(jīng)理面試的高頻話(huà)題??闪炕Ч媚憧梢越o出“SQL 生成準(zhǔn)確率”“查詢(xún)響應(yīng)時(shí)間”“端到端任務(wù)完成率”等指標(biāo)這些都是作品集里的硬通貨。能獨(dú)立完成借助 Vibe Coding一個(gè)人就能搭出可演示的版本不需要依賴(lài)后端團(tuán)隊(duì)、數(shù)據(jù)團(tuán)隊(duì)和測(cè)試資源。1.4 容易混淆的概念澄清很多初學(xué)者會(huì)把幾個(gè)相關(guān)概念搞混概念核心能力與 ChatBI 的區(qū)別傳統(tǒng) BITableau、Power BI可視化報(bào)表、拖拽分析需要用戶(hù)手動(dòng)配置圖表和指標(biāo)學(xué)習(xí)成本高Chatbot智能客服對(duì)話(huà)問(wèn)答、任務(wù)辦理偏向服務(wù)交互不一定涉及數(shù)據(jù)庫(kù)查詢(xún)ChatBI自然語(yǔ)言 → 數(shù)據(jù)查詢(xún) → 分析與展示強(qiáng)調(diào)“對(duì)話(huà)即分析”核心是理解和查詢(xún)數(shù)據(jù)Copilot編程助手在 IDE 里輔助寫(xiě)代碼面向研發(fā)場(chǎng)景不是面向業(yè)務(wù)分析場(chǎng)景搞清楚這些邊界寫(xiě)簡(jiǎn)歷時(shí)才能精確表達(dá)自己作品集的定位。2. 環(huán)境準(zhǔn)備與工具選型做作品集不需要企業(yè)級(jí)技術(shù)架構(gòu)我們的原則是夠用、開(kāi)源、免費(fèi)、演示順暢。2.1 我選擇的工具鏈下面是我個(gè)人的方案你可以根據(jù)手頭資源調(diào)整用途工具選擇選型理由Vibe Coding 主環(huán)境Cursor 或 Claude / DeepSeek 對(duì)話(huà)窗口Cursor 適合邊聊邊改代碼對(duì)話(huà)式工具適合快速生成完整腳本編程語(yǔ)言Python 3.10AI 生成代碼最容易穩(wěn)定運(yùn)行的語(yǔ)言生態(tài)完善前后端框架Streamlit純 Python 寫(xiě) Web 應(yīng)用幾百行代碼就能做出像樣的界面數(shù)據(jù)庫(kù)SQLite無(wú)需安裝數(shù)據(jù)庫(kù)服務(wù)單文件存儲(chǔ)作品集演示零成本向量數(shù)據(jù)庫(kù)ChromaDB用于存放樣例問(wèn)題和 SQL 模板提升 NL2SQL 準(zhǔn)確率LLM APIOpenAI GPT-4o / DeepSeek / Qwen任選其一即可取決于你的預(yù)算和可用性依賴(lài)管理requirements.txt pip保持環(huán)境簡(jiǎn)單方便他人復(fù)現(xiàn)2.2 需要確認(rèn)的版本說(shuō)明我必須先聲明大模型相關(guān) API 和工具版本變化非??煜旅娼o出的版本號(hào)只是說(shuō)明我在寫(xiě)這篇文章時(shí)的常見(jiàn)選擇。你實(shí)際使用時(shí)請(qǐng)以官方最新文檔為準(zhǔn)不要照搬。# 建議使用 Python 3.10 或 3.11 python --version # 安裝核心依賴(lài)注意版本可能隨時(shí)間更新 pip install streamlit pip install openai pip install langchain pip install chromadb pip install pandas pip install sqlite3 # 一般內(nèi)置無(wú)需單獨(dú)安裝如果你所在的網(wǎng)絡(luò)環(huán)境不方便直接訪問(wèn)部分外部服務(wù)可以選擇國(guó)內(nèi)可用的模型服務(wù)商或者通過(guò)代理方式訪問(wèn)這里不展開(kāi)。2.3 示例項(xiàng)目結(jié)構(gòu)我在做這個(gè)作品集時(shí)項(xiàng)目目錄如下chatbi-mvp/ ├── app.py # Streamlit 入口頁(yè)面 ├── nl2sql.py # 核心模塊自然語(yǔ)言轉(zhuǎn) SQL ├── database/ │ ├── init_db.py # 初始化數(shù)據(jù)庫(kù)和樣例數(shù)據(jù) │ └── sales.db # SQLite 數(shù)據(jù)庫(kù)文件 ├── prompts/ │ └── sql_prompt.py # Prompt 模板 ├── examples/ │ └── few_shot_examples.py # 少樣本示例用于提升準(zhǔn)確率 ├── requirements.txt └── README.md這個(gè)結(jié)構(gòu)夠清晰面試官一眼能看出你對(duì)項(xiàng)目有工程化思維而不是把代碼堆在一個(gè)文件里。3. Vibe Coding 實(shí)操方法論從想法到原型這一節(jié)是整篇文章最關(guān)鍵的部分。我不會(huì)直接給你一堆代碼而是先講 Vibe Coding 的操作方法。因?yàn)橹挥姓莆樟诉@套方法你以后才能快速做出不同主題的作品集。3.1 第一輪用自然語(yǔ)言讓 AI 生成腳手架我第一次做 ChatBI 原型時(shí)沒(méi)有先寫(xiě)架構(gòu)文檔而是直接打開(kāi) Cursor輸入了這樣一段 Prompt你是一名 Python 開(kāi)發(fā)工程師請(qǐng)幫我搭建一個(gè) ChatBI MVP 項(xiàng)目的骨架。 要求如下 1. 使用 Streamlit 作為 Web 界面框架 2. 用戶(hù)輸入中文問(wèn)題系統(tǒng)返回 SQL 查詢(xún)語(yǔ)句、執(zhí)行結(jié)果和圖表 3. 數(shù)據(jù)庫(kù)使用 SQLite提前生成一個(gè)銷(xiāo)售訂單表包含 100 條左右的測(cè)試數(shù)據(jù)字段包括 - order_id - order_date - region - product_category - sales_amount - quantity 4. 先別寫(xiě)完整功能只生成項(xiàng)目目錄結(jié)構(gòu)和每個(gè)文件的占位代碼。 請(qǐng)直接輸出每個(gè)文件的完整代碼。這段 Prompt 的關(guān)鍵信息非常明確技術(shù)棧、數(shù)據(jù)表結(jié)構(gòu)、輸出格式要求。AI 生成的代碼一開(kāi)始當(dāng)然不完美但不重要。第一輪的目標(biāo)是拿到一個(gè)能跑起來(lái)的骨架。3.2 第二輪逐模塊迭代而不是一次到位拿到骨架后不要急著讓 AI 一次性把所有功能全部補(bǔ)齊那樣很容易生成一大堆互相不兼容的代碼。我的建議是把完整需求拆成下面幾個(gè)模塊分別對(duì)話(huà)解決模塊一數(shù)據(jù)初始化讓 SQLite 有數(shù)據(jù)可查模塊二LLM 調(diào)用封裝讓程序可以請(qǐng)求大模型接口模塊三NL2SQL 核心邏輯自然語(yǔ)言轉(zhuǎn)成 SQL 語(yǔ)句模塊四結(jié)果解析與可視化把查詢(xún)結(jié)果渲染成圖表模塊五異常處理SQL 生成錯(cuò)誤時(shí)給出兜底方案每次對(duì) AI 只提一個(gè)小需求。比如請(qǐng)給 nl2sql.py 寫(xiě)一個(gè)函數(shù)輸入是用戶(hù)問(wèn)題中文輸出是一條 SQL 查詢(xún)語(yǔ)句。 要求 1. 先獲取數(shù)據(jù)表的 schema也就是表名、字段名、字段類(lèi)型和主鍵信息 2. 把 schema 和 few-shot 示例一起放進(jìn) Prompt 3. 解析 LLM 返回的 SQL去掉 markdown 格式代碼塊標(biāo)記 4. 如果生成失敗返回空字符串。這樣做的優(yōu)勢(shì)是每個(gè)模塊的代碼都短小、邏輯清晰即使出現(xiàn) Bug 也容易定位。這就是 Vibe Coding 和傳統(tǒng)開(kāi)發(fā)的典型差異——我們通過(guò)“對(duì)話(huà) 小步迭代”替代了“一次性編碼”。3.3 第三輪運(yùn)行、報(bào)錯(cuò)、反饋、優(yōu)化Vibe Coding 的本質(zhì)不只是讓 AI 寫(xiě)代碼還包括讓 AI 幫你改代碼。運(yùn)行報(bào)錯(cuò)時(shí)直接把錯(cuò)誤信息復(fù)制回對(duì)話(huà)窗口運(yùn)行 app.py 時(shí)出現(xiàn)以下報(bào)錯(cuò)請(qǐng)分析原因并給出修復(fù)后的代碼。 Streamlit run app.py 報(bào)錯(cuò)信息 sqlite3.OperationalError: table sales_orders has no column named order_dateAI 能根據(jù)報(bào)錯(cuò)信息迅速定位問(wèn)題通常是因?yàn)槲覀兂跏蓟瘮?shù)據(jù)庫(kù)時(shí)字段名不一致。它會(huì)把相關(guān)代碼段重新生成一遍你復(fù)制覆蓋即可。這個(gè)“運(yùn)行-報(bào)錯(cuò)-反饋-修復(fù)”的循環(huán)就是 Vibe Coding 的核心工作流。你要習(xí)慣把自己當(dāng)成項(xiàng)目經(jīng)理和測(cè)試人員而不是“打字員”。3.4 關(guān)于“避免幻覺(jué)功能”的提醒使用 Vibe Coding 時(shí)最大的風(fēng)險(xiǎn)是讓 AI 生成了它“以為自己能做”但實(shí)際運(yùn)行不了的功能。比如讓它接入一些并不存在的第三方 API或者編造不存在的 Python 庫(kù)。我的規(guī)避方法有兩條在 Prompt 里明確要求使用主流、成熟、真實(shí)存在的庫(kù)拿到 AI 給的代碼后先看它 import 了哪些庫(kù)逐個(gè)確認(rèn)這些庫(kù)是否真實(shí)存在、是否能正常安裝。如果 AI 給出的某個(gè)庫(kù)你從來(lái)沒(méi)聽(tīng)說(shuō)過(guò)不要直接相信先去 PyPI 或 GitHub 搜一下再?zèng)Q定。這是 AI 產(chǎn)品經(jīng)理應(yīng)該養(yǎng)成的技術(shù)敬畏心。4. 實(shí)戰(zhàn)用 Vibe Coding 從零構(gòu)建 ChatBI 最小可行版本下面進(jìn)入完整實(shí)戰(zhàn)環(huán)節(jié)。我盡量把每一步寫(xiě)清楚讓你可以照著做出來(lái)。4.1 初始化數(shù)據(jù)庫(kù)與樣例數(shù)據(jù)首先準(zhǔn)備好數(shù)據(jù)。在項(xiàng)目根目錄創(chuàng)建database/init_db.py。# 文件路徑database/init_db.py import sqlite3 import random from datetime import datetime, timedelta def create_database(db_pathdatabase/sales.db): conn sqlite3.connect(db_path) cursor conn.cursor() # 創(chuàng)建銷(xiāo)售訂單表 cursor.execute( CREATE TABLE IF NOT EXISTS sales_orders ( order_id INTEGER PRIMARY KEY AUTOINCREMENT, order_date TEXT NOT NULL, region TEXT NOT NULL, product_category TEXT NOT NULL, sales_amount REAL NOT NULL, quantity INTEGER NOT NULL ) ) # 生成測(cè)試數(shù)據(jù) regions [華東, 華南, 華北, 西南] categories [數(shù)碼產(chǎn)品, 家用電器, 服飾鞋包, 食品飲料] start_date datetime(2024, 1, 1) random.seed(42) # 固定隨機(jī)種子保證數(shù)據(jù)可復(fù)現(xiàn) for i in range(200): order_date start_date timedelta(daysrandom.randint(0, 365)) region random.choice(regions) category random.choice(categories) amount round(random.uniform(50, 2000), 2) quantity random.randint(1, 10) cursor.execute( INSERT INTO sales_orders (order_date, region, product_category, sales_amount, quantity) VALUES (?, ?, ?, ?, ?), (order_date.strftime(%Y-%m-%d), region, category, amount, quantity) ) conn.commit() conn.close() print(數(shù)據(jù)庫(kù)初始化完成共插入 200 條銷(xiāo)售訂單。) if __name__ __main__: create_database()運(yùn)行初始化腳本python database/init_db.py預(yù)期輸出數(shù)據(jù)庫(kù)初始化完成共插入 200 條銷(xiāo)售訂單。這個(gè)腳本有三個(gè)教學(xué)點(diǎn)值得你在簡(jiǎn)歷里提到字段設(shè)計(jì)、隨機(jī)種子保證數(shù)據(jù)可復(fù)現(xiàn)、SQLite 輕量化的選型理由。4.2 編寫(xiě) Prompt 模板與少樣本示例NL2SQL 的核心是 Prompt 設(shè)計(jì)。我們要讓模型知道有哪些表、哪些字段、用戶(hù)的問(wèn)題是什么意思、應(yīng)該生成什么 SQL。先創(chuàng)建prompts/sql_prompt.py# 文件路徑prompts/sql_prompt.py def build_sql_prompt(schema_text: str, examples_text: str, user_question: str) - str: prompt f 你是一個(gè)數(shù)據(jù)分析師負(fù)責(zé)把用戶(hù)的中文問(wèn)題轉(zhuǎn)換成 SQL 查詢(xún)語(yǔ)句。 請(qǐng)嚴(yán)格遵循以下規(guī)則 1. 只能根據(jù)給定的表結(jié)構(gòu)生成 SQL不能臆造不存在的字段 2. 只輸出 SQL 語(yǔ)句本身不要輸出解釋、不要使用 Markdown 代碼塊標(biāo)記 3. 查詢(xún)結(jié)果必須是聚合后的匯總數(shù)據(jù)不允許返回明細(xì)行 4. 如果用戶(hù)問(wèn)題中指定了時(shí)間范圍要使用 WHERE 條件進(jìn)行過(guò)濾 5. 金額相關(guān)字段需要輸出保留兩位小數(shù) 6. 如果問(wèn)題無(wú)法用給定表結(jié)構(gòu)回答請(qǐng)輸出: ERROR: 無(wú)法生成查詢(xún) 數(shù)據(jù)庫(kù)表結(jié)構(gòu)如下 {schema_text} 參考示例 {examples_text} 用戶(hù)問(wèn)題{user_question} SQL: return prompt再創(chuàng)建examples/few_shot_examples.py這里放了幾個(gè)典型問(wèn)題用來(lái)引導(dǎo)模型生成風(fēng)格統(tǒng)一的 SQL# 文件路徑examples/few_shot_examples.py FEW_SHOT_EXAMPLES [ { question: 上個(gè)月華東區(qū)域的銷(xiāo)售額是多少, sql: SELECT region, ROUND(SUM(sales_amount), 2) AS total_sales FROM sales_orders WHERE region 華東 AND order_date BETWEEN 2024-11-01 AND 2024-11-30 GROUP BY region }, { question: 哪個(gè)產(chǎn)品類(lèi)別累計(jì)銷(xiāo)售額最高, sql: SELECT product_category, ROUND(SUM(sales_amount), 2) AS total_sales FROM sales_orders GROUP BY product_category ORDER BY total_sales DESC LIMIT 1 }, { question: 西南區(qū)域今年第一季度各個(gè)月份的訂單數(shù)量趨勢(shì)如何, sql: SELECT strftime(%Y-%m, order_date) AS month, COUNT(*) AS order_cnt FROM sales_orders WHERE region 西南 AND order_date BETWEEN 2024-01-01 AND 2024-03-31 GROUP BY month ORDER BY month }, { question: 華南區(qū)域銷(xiāo)量最高的商品類(lèi)別是哪一類(lèi), sql: SELECT product_category, SUM(quantity) AS total_quantity FROM sales_orders WHERE region 華南 GROUP BY product_category ORDER BY total_quantity DESC LIMIT 1 }, { question: 最近一個(gè)月平均每筆訂單的金額是多少, sql: SELECT ROUND(AVG(sales_amount), 2) AS avg_order_amount FROM sales_orders WHERE order_date 2024-11-30 - INTERVAL 30 DAY }, ]需要說(shuō)明的是最后一個(gè)示例里的INTERVAL語(yǔ)法在 SQLite 中不一定直接生效實(shí)際使用時(shí)應(yīng)統(tǒng)一用字符串日期比較。這里保留原樣是想提醒你AI 生成的 SQL 并不總是和數(shù)據(jù)庫(kù)方言匹配審查 SQL 是產(chǎn)品經(jīng)理必須具備的能力。因此我們?cè)谶\(yùn)行時(shí)會(huì)對(duì)生成的 SQL 做兩層校驗(yàn)下面會(huì)講到。4.3 編寫(xiě)獲取 Schema 的工具函數(shù)要讓模型寫(xiě)出正確 SQL必須把數(shù)據(jù)庫(kù)結(jié)構(gòu)告訴它。寫(xiě)一個(gè)工具函數(shù)用 SQLite 的系統(tǒng)表查詢(xún)字段信息# 文件路徑nl2sql.py部分代碼 import sqlite3 def get_schema(db_path: str database/sales.db) - str: conn sqlite3.connect(db_path) cursor conn.cursor() cursor.execute(SELECT name FROM sqlite_master WHERE typetable) tables [row[0] for row in cursor.fetchall()] schema_parts [] for table in tables: cursor.execute(fPRAGMA table_info({table})) columns cursor.fetchall() col_desc , .join([f{col[1]} {col[2]} for col in columns]) schema_parts.append(f表名: {table}, 字段: {col_desc}) conn.close() return \n.join(schema_parts)這里用PRAGMA table_info獲取字段名和類(lèi)型信息足夠簡(jiǎn)潔適合放進(jìn) Prompt。需要說(shuō)明的是這里的fPRAGMA table_info({table})屬于內(nèi)部信任場(chǎng)景因?yàn)楸砻麃?lái)自系統(tǒng)表不是直接拼接用戶(hù)輸入因此在演示場(chǎng)景下風(fēng)險(xiǎn)可控。如果對(duì)接真實(shí)業(yè)務(wù)庫(kù)不能直接這樣寫(xiě)應(yīng)該使用參數(shù)化查詢(xún)方式獲取元數(shù)據(jù)。4.4 編寫(xiě) NC2SQL 主流程下面來(lái)寫(xiě)nl2sql.py的完整核心邏輯。它負(fù)責(zé)四件事獲取 Schema、調(diào)用模型生成 SQL、校驗(yàn) SQL、執(zhí)行 SQL。# 文件路徑nl2sql.py import re import sqlite3 from openai import OpenAI from prompts.sql_prompt import build_sql_prompt from examples.few_shot_examples import FEW_SHOT_EXAMPLES client OpenAI(api_keyyour-api-key, base_urlyour-base-url) # 取決于你的模型服務(wù)商 def get_schema(db_path: str database/sales.db) - str: # 省略同上文 get_schema 函數(shù) def extract_sql(text: str) - str: 從模型輸出中提取純 SQL去掉可能的 markdown 標(biāo)記 # 去掉代碼塊標(biāo)記 text re.sub(rsql|, , text).strip() return text def validate_sql(sql: str) - bool: 簡(jiǎn)單校驗(yàn) SQL 是否包含風(fēng)險(xiǎn)或異常語(yǔ)法 blacklist [INSERT, UPDATE, DELETE, DROP, ALTER, CREATE] for word in blacklist: if re.search(r\b word r\b, sql.upper()): return False return True def execute_sql(sql: str, db_path: str database/sales.db): conn sqlite3.connect(db_path) try: cursor conn.cursor() cursor.execute(sql) columns [desc[0] for desc in cursor.description] if cursor.description else [] rows cursor.fetchall() return columns, rows except Exception as e: return None, f執(zhí)行錯(cuò)誤: {e} finally: conn.close() def nl2sql(user_question: str) - dict: schema get_schema() examples_text for item in FEW_SHOT_EXAMPLES: examples_text f問(wèn)題: {item[question]}\nSQL: {item[sql]}\n\n prompt build_sql_prompt(schema, examples_text, user_question) response client.chat.completions.create( modelgpt-4o, messages[{role: user, content: prompt}], temperature0.1, ) raw_sql response.choices[0].message.content sql extract_sql(raw_sql) # 判斷是否生成失敗 if sql.startswith(ERROR) or sql : return {error: 無(wú)法理解該問(wèn)題請(qǐng)嘗試換個(gè)說(shuō)法。} # 判斷是否包含非法 SQL if not validate_sql(sql): return {error: 生成的 SQL 存在安全風(fēng)險(xiǎn)已阻止執(zhí)行。} # 執(zhí)行 SQL columns, rows execute_sql(sql) if columns is None: return {error: rows} return {columns: columns, rows: rows, sql: sql}關(guān)鍵步驟說(shuō)明temperature0.1讓模型輸出更穩(wěn)定減少隨意生成。extract_sql是為了兼容不同模型輸出格式有的模型喜歡帶 markdown 代碼塊。validate_sql是安全兜底避免模型生成非查詢(xún)語(yǔ)句。這很重要正式做 ChatBI 時(shí)不能直接執(zhí)行模型生成的 SQL。execute_sql捕獲執(zhí)行異常保證至少不會(huì)讓整個(gè) Web 應(yīng)用崩潰。4.5 編寫(xiě)圖表可視化邏輯為了讓作品集看起來(lái)更完整我們?cè)谀玫讲樵?xún)結(jié)果后嘗試根據(jù)字段特征自動(dòng)判斷是否適合畫(huà)圖。# 文件路徑app.py部分代碼 import pandas as pd import streamlit as st from nl2sql import nl2sql import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS, PingFang SC] plt.rcParams[axes.unicode_minus] False def auto_visualize(columns, rows): 根據(jù)返回的字段做簡(jiǎn)單的可視化判斷。 如果只有一個(gè)維度字段和一個(gè)數(shù)值字段輸出柱狀圖或折線圖。 df pd.DataFrame(rows, columnscolumns) if len(df.columns) 2: first_col df.columns[0] second_col df.columns[1] if pd.api.types.is_numeric_dtype(df[second_col]): fig, ax plt.subplots(figsize(10, 5)) ax.bar(df[first_col].astype(str), df[second_col]) ax.set_xlabel(first_col) ax.set_ylabel(second_col) ax.set_title(f{first_col} vs {second_col}) plt.xticks(rotation45, haright) st.pyplot(fig)這一步不用太復(fù)雜關(guān)鍵是讓面試官和用戶(hù)直觀感受到“系統(tǒng)不僅能問(wèn)答還能自動(dòng)給出圖表”。4.6 編寫(xiě) Streamlit 界面最后是 Web 界面層。我們希望用戶(hù)輸入一個(gè)問(wèn)題點(diǎn)擊按鈕看到三個(gè)東西生成的 SQL、查詢(xún)結(jié)果表格、對(duì)應(yīng)圖表。# 文件路徑app.py import streamlit as st import pandas as pd from nl2sql import nl2sql def auto_visualize(columns, rows): # 省略同上文 def main(): st.set_page_config(page_titleChatBI 數(shù)據(jù)問(wèn)答助手, layoutwide) st.title( ChatBI 數(shù)據(jù)問(wèn)答助手) st.caption(輸入你的業(yè)務(wù)問(wèn)題系統(tǒng)將自動(dòng)完成 SQL 生成、執(zhí)行與可視化展示。) user_question st.text_input(請(qǐng)輸入你的問(wèn)題, placeholder比如華東區(qū)域銷(xiāo)售額最高的商品類(lèi)別是什么) if st.button(開(kāi)始分析, typeprimary): if not user_question.strip(): st.warning(請(qǐng)先輸入問(wèn)題。) return with st.spinner(正在理解和生成查詢(xún)...): result nl2sql(user_question) if error in result: st.error(result[error]) return st.subheader(生成的 SQL) st.code(result[sql], languagesql) st.subheader(查詢(xún)結(jié)果) columns result[columns] rows result[rows] df pd.DataFrame(rows, columnscolumns) st.dataframe(df, use_container_widthTrue) st.subheader(可視化分析) auto_visualize(columns, rows) if __name__ __main__: main()運(yùn)行方式streamlit run app.py瀏覽器會(huì)自動(dòng)打開(kāi)http://localhost:8501。輸入中文問(wèn)題就能看到完整的問(wèn)答分析過(guò)程。4.7 運(yùn)行效果預(yù)期當(dāng)你輸入“華東區(qū)域銷(xiāo)售額最高的商品類(lèi)別是什么”時(shí)預(yù)期輸出大致是生成的 SQLSELECT product_category, ROUND(SUM(sales_amount), 2) AS total_sales FROM sales_orders WHERE region 華東 GROUP BY product_category ORDER BY total_sales DESC LIMIT 1數(shù)據(jù)表格一列是商品類(lèi)別一列是累計(jì)銷(xiāo)售額按降序排列??梢暬瘓D表因?yàn)榈谝涣惺亲址⒌诙惺菙?shù)值系統(tǒng)自動(dòng)繪制柱狀圖。雖然這個(gè) MVP 還不夠智能但它已經(jīng)是一個(gè)完整的 ChatBI 閉環(huán)足夠放進(jìn)作品集里講清楚產(chǎn)品邏輯。5. 進(jìn)階提升讓 ChatBI 更接近真實(shí)產(chǎn)品只跑通一個(gè)簡(jiǎn)單 Demo 是不夠的AI 產(chǎn)品經(jīng)理的作品集一定要體現(xiàn)“思考深度”。下面這幾個(gè)方向你可以選 1 到 2 個(gè)在作品集里展示。5.1 加入語(yǔ)義緩存機(jī)制在很多 ChatBI 場(chǎng)景中用戶(hù)會(huì)反復(fù)問(wèn)類(lèi)似的問(wèn)題。如果每次都調(diào)用大模型生成 SQL成本高、響應(yīng)慢。一個(gè)簡(jiǎn)單有效的優(yōu)化是引入語(yǔ)義緩存。思路先把用戶(hù)問(wèn)題轉(zhuǎn)成 embedding 向量然后在 ChromaDB 里查找最相似的歷史問(wèn)題。如果相似度超過(guò)一個(gè)閾值比如 0.85直接返回歷史 SQL 和結(jié)果。# 思路示例語(yǔ)義緩存 from chromadb import Client # 1. 初始化 Chroma 集合 # 2. 將每個(gè)歷史問(wèn)題寫(xiě)入 collection同時(shí)存儲(chǔ) SQL 和結(jié)果 # 3. 用戶(hù)提問(wèn)時(shí)先用 embedding 搜索相似記錄 # 4. 相似度高直接返回否則走 NL2SQL 主鏈路這個(gè)機(jī)制進(jìn)簡(jiǎn)歷非常加分因?yàn)樗w現(xiàn)你考慮了成本、性能和產(chǎn)品體驗(yàn)的平衡。5.2 加入多輪對(duì)話(huà)能力上面的 MVP 只支持單輪對(duì)話(huà)。真實(shí)產(chǎn)品中用戶(hù)會(huì)追問(wèn)“那華北呢”“占比是多少”這些問(wèn)題依賴(lài)上下文。優(yōu)化思路有兩種簡(jiǎn)單法把歷史對(duì)話(huà)記錄拼進(jìn) Prompt讓模型自己理解當(dāng)前問(wèn)題是否依賴(lài)上文。結(jié)構(gòu)法在對(duì)話(huà)歷史中抽取實(shí)體和條件區(qū)域、時(shí)間、品類(lèi)填充一個(gè)“查詢(xún)條件槽位”。作為作品集建議先實(shí)現(xiàn)簡(jiǎn)單法后說(shuō)明結(jié)構(gòu)法的演進(jìn)方向。5.3 加入數(shù)據(jù)權(quán)限控制真實(shí) ChatBI 最重要的工程問(wèn)題之一是數(shù)據(jù)權(quán)限。不是所有用戶(hù)都有權(quán)限查看所有區(qū)域的數(shù)據(jù)。你可以在作品集里加上一個(gè)簡(jiǎn)單的角色權(quán)限模型# 思路示例權(quán)限控制 # 1. 定義用戶(hù)角色比如 admin、analyst、visitor # 2. 根據(jù)角色生成不同的 SQL 過(guò)濾條件 # 3. 例如 visitor 只在 WHERE 條件中強(qiáng)制追加 user_region 華東 # 4. 在原型中通過(guò)側(cè)邊欄切換角色演示不同身份看到的數(shù)據(jù)范圍不同這個(gè)功能不用寫(xiě)得很復(fù)雜但一定要在 README 和簡(jiǎn)歷里說(shuō)明因?yàn)檫@直接展示了你作為 AI 產(chǎn)品經(jīng)理對(duì)“安全邊界”的理解。6. 如何把 ChatBI 作品集寫(xiě)進(jìn)簡(jiǎn)歷作品集做出來(lái)了最關(guān)鍵的一步來(lái)了怎么在簡(jiǎn)歷里展示它。6.1 簡(jiǎn)歷項(xiàng)目描述通用框架我建議參考 STAR 法則但寫(xiě)簡(jiǎn)歷時(shí)不需要嚴(yán)格寫(xiě)成四段。核心是讓面試官在 30 秒內(nèi)看懂三個(gè)信息背景、動(dòng)作、結(jié)果。信息項(xiàng)內(nèi)容建議項(xiàng)目背景一句話(huà)說(shuō)明為什么做這個(gè) ChatBI時(shí)間跨度寫(xiě)清楚周期最好在 2-4 周內(nèi)你的角色獨(dú)立完成或作為 AI 產(chǎn)品經(jīng)理主導(dǎo)核心動(dòng)作Vibe Coding、Prompt 工程、NL2SQL、可視化、安全機(jī)制量化結(jié)果SQL 生成準(zhǔn)確率、響應(yīng)時(shí)間、功能覆蓋率技術(shù)棧Python、Streamlit、SQLite、LLM API6.2 簡(jiǎn)歷項(xiàng)目描述示例下面給一個(gè)可以直接參考的寫(xiě)法注意替換為你的實(shí)際數(shù)據(jù)和指標(biāo)ChatBI 對(duì)話(huà)式數(shù)據(jù)分析助手獨(dú)立開(kāi)發(fā) / 2025.03 - 2025.04 項(xiàng)目背景 企業(yè)內(nèi)部運(yùn)營(yíng)人員日常取數(shù)依賴(lài)數(shù)據(jù)團(tuán)隊(duì)大量常見(jiàn)問(wèn)題通過(guò)即時(shí)通訊工具紙質(zhì)傳遞查詢(xún)效率低、口徑不一致。 項(xiàng)目動(dòng)作 - 基于 Vibe Coding 方法論使用 Python Streamlit 完成 ChatBI MVP 從需求拆解到可運(yùn)行原型 - 設(shè)計(jì) NL2SQL 核心鏈路通過(guò) LLM 將中文問(wèn)題轉(zhuǎn)換為 SQL結(jié)合 sqlite schema 注入、few-shot 示例增強(qiáng)生成準(zhǔn)確率 - 設(shè)計(jì)結(jié)果可視化模塊根據(jù)字段類(lèi)型自動(dòng)選擇柱狀圖、折線圖或明細(xì)表展示 - 加入語(yǔ)義緩存、多輪對(duì)話(huà)擴(kuò)展方案降低接口調(diào)用成本 - 設(shè)計(jì)用戶(hù)角色與數(shù)據(jù)權(quán)限控制邏輯確保不同角色只能查看授權(quán)范圍內(nèi)的數(shù)據(jù)。 量化結(jié)果 - 在 200 條銷(xiāo)售訂單數(shù)據(jù)上常見(jiàn)業(yè)務(wù)問(wèn)題的 SQL 生成準(zhǔn)確率達(dá)到約 92% - 將語(yǔ)義緩存命中后的查詢(xún)響應(yīng)從平均 8 秒降低至 1 秒以?xún)?nèi) - MVP 從需求確定到可演示版本交付耗時(shí) 2 周全程獨(dú)立完成 - 沉淀了一套可復(fù)用的 NL2SQL 提示詞模板和 SQL 安全校驗(yàn)規(guī)則。 技術(shù)棧Python、Streamlit、SQLite、ChromaDB、OpenAI API / DeepSeek API需要提醒的是準(zhǔn)確率 92% 這種數(shù)字不能拍腦袋亂寫(xiě)。我的建議是自己在測(cè)試集上跑一遍記錄真實(shí)結(jié)果后填進(jìn)去。哪怕準(zhǔn)確率只有 75%只要說(shuō)明測(cè)試條件和改進(jìn)路徑也比虛標(biāo)數(shù)字更有說(shuō)服力。6.3 面試時(shí)如何講解這個(gè)作品集面試官通常會(huì)從三個(gè)角度追問(wèn)技術(shù)理解類(lèi)NL2SQL 的難點(diǎn)是什么幻覺(jué)問(wèn)題怎么處理產(chǎn)品判斷類(lèi)為什么選 ChatBI 這個(gè)場(chǎng)景目標(biāo)用戶(hù)是誰(shuí)工程落地類(lèi)模型返回錯(cuò)誤 SQL 怎么辦如何防止用戶(hù)越權(quán)查數(shù)建議在本地留一個(gè)可運(yùn)行的 Demo 包面試時(shí)直接打開(kāi) Streamlit 現(xiàn)場(chǎng)演示。這比任何口頭描述都有說(shuō)服力。你需要準(zhǔn)備好一段 3 分鐘的演示腳本講清楚“用戶(hù)輸入問(wèn)題 → 生成 SQL → 執(zhí)行 → 可視化”的完整流程。7. 常見(jiàn)問(wèn)題與排查思路7.1 常見(jiàn)問(wèn)題匯總問(wèn)題現(xiàn)象常見(jiàn)原因解決思路輸入問(wèn)題后長(zhǎng)時(shí)間無(wú)響應(yīng)LLM API 響應(yīng)慢或網(wǎng)絡(luò)不穩(wěn)定檢查 API 服務(wù)狀態(tài)設(shè)置超時(shí)時(shí)間落地語(yǔ)義緩存模型生成的 SQL 執(zhí)行報(bào)錯(cuò)字段名與 schema 不一致在 Prompt 中強(qiáng)調(diào)只使用給定字段查看報(bào)錯(cuò)信息反饋給 AI 修復(fù)SQL 能執(zhí)行但結(jié)果明顯不對(duì)缺少 WHERE 條件或聚合方式錯(cuò)誤補(bǔ)充 few-shot 示例降低 temperature中文圖表亂碼matplotlib 缺少中文字體設(shè)置字體為 SimHei 或 PingFang SCStreamlit 頁(yè)面打不開(kāi)端口被占用或依賴(lài)未裝齊檢查streamlit run app.py的啟動(dòng)日志嘗試換端口數(shù)據(jù)庫(kù)大量重復(fù)數(shù)據(jù)重復(fù)運(yùn)行 init_db.py在腳本里增加刪除舊表或判斷是否已存在的邏輯7.2 排查優(yōu)先級(jí)清單如果系統(tǒng)跑不通不要慌按下面的順序排查數(shù)據(jù)庫(kù)是否有數(shù)據(jù)打開(kāi)database/sales.db確認(rèn)sales_orders表非空API 是否可用在 Python 里單獨(dú)測(cè)試一次client.chat.completions.create看能否返回內(nèi)容Prompt 是否正確拼接打印出build_sql_prompt的完整輸出檢查 schema 和 examples 是否有語(yǔ)法問(wèn)題SQL 校驗(yàn)是否過(guò)嚴(yán)確認(rèn)沒(méi)有誤殺合法的 SELECT 語(yǔ)句頁(yè)面渲染是否出錯(cuò)查看 Streamlit 終端的完整 traceback定位到具體行號(hào)。8. 最佳實(shí)踐與工程建議8.1 Vibe Coding 過(guò)程的工程素養(yǎng)Vibe Coding 不等于“沒(méi)有工程素養(yǎng)”。恰恰相反AI 產(chǎn)品經(jīng)理更應(yīng)該具備工程思維否則很容易被 AI 生成的一堆花哨代碼帶偏。幾點(diǎn)建議版本控制必須有哪怕是小項(xiàng)目也建議用 Git 管理否則改壞了無(wú)法回退。每個(gè)版本“能跑即提交”不要等技術(shù)債積累太多才想起保存。記錄 Prompt 迭代過(guò)程你每次怎么修改 Prompt 才讓模型輸出變好這是 AI 產(chǎn)品經(jīng)理作品集里的隱形資產(chǎn)。保持項(xiàng)目結(jié)構(gòu)整潔即使代碼是 AI 寫(xiě)的也要堅(jiān)持模塊化拆分不要一個(gè)文件寫(xiě) 800 行。8.2 安全邊界這是 ChatBI 類(lèi)作品最重要的部分絕不能讓模型生成的 SQL 直接在生產(chǎn)庫(kù)上執(zhí)行必須加白名單機(jī)制、SQL 校驗(yàn)和資源限制明確定義安全邊界作品集演示可以用 SQLite但簡(jiǎn)歷里一定要寫(xiě)清楚“正式方案中需要接入查詢(xún)網(wǎng)關(guān)、數(shù)據(jù)脫敏、行級(jí)權(quán)限”提示詞注入風(fēng)險(xiǎn)不要在業(yè)務(wù)數(shù)據(jù)中直接拼接用戶(hù)輸入到 Prompt 之外的部分涉及真實(shí)數(shù)據(jù)時(shí)必須經(jīng)過(guò)授權(quán)和脫敏處理。8.3 效果評(píng)估方法ChatBI 不是“能跑就行”。一個(gè)合格的數(shù)據(jù)分析助手必須有一套評(píng)估維度評(píng)估維度說(shuō)明評(píng)估方式查詢(xún)生成準(zhǔn)確率生成的 SQL 是否與預(yù)期結(jié)果一致構(gòu)建測(cè)試集人工標(biāo)注端到端成功率用戶(hù)提問(wèn)后是否成功返回結(jié)果日志統(tǒng)計(jì)響應(yīng)時(shí)間從提問(wèn)到結(jié)果展示的總耗時(shí)日志統(tǒng)計(jì)用戶(hù)滿(mǎn)意率用戶(hù)對(duì)回答是否滿(mǎn)意問(wèn)卷或反饋按鈕兜底率無(wú)法回答時(shí)是否有友好提示日志統(tǒng)計(jì)建議在作品集 README 里寫(xiě)清楚評(píng)估方式和測(cè)試結(jié)果這比“Demo 做得很炫”更有專(zhuān)業(yè)深度。9. 總結(jié)與下一步行動(dòng)路線9.1 你已經(jīng)掌握了什么通過(guò)這篇文章你已經(jīng)了解到Vibe Coding 的核心工作流自然語(yǔ)言 → 生成代碼 → 運(yùn)行報(bào)錯(cuò) → 反饋修復(fù) → 迭代優(yōu)化從零構(gòu)建 ChatBI MVP 的完整鏈路數(shù)據(jù)準(zhǔn)備、Prompt 設(shè)計(jì)、NL2SQL、業(yè)務(wù)校驗(yàn)、可視化展示ChatBI 產(chǎn)品在真實(shí)落地時(shí)需要關(guān)注的進(jìn)階能力語(yǔ)義緩存、多輪對(duì)話(huà)、數(shù)據(jù)權(quán)限控制如何把一個(gè)作品集項(xiàng)目專(zhuān)業(yè)地寫(xiě)進(jìn)簡(jiǎn)歷并準(zhǔn)備好面試講解路徑。9.2 下一步推薦做什么我一直強(qiáng)調(diào)AI 產(chǎn)品經(jīng)理最重要的不是堆代碼量而是形成“定義問(wèn)題 - 快速驗(yàn)證 - 量化評(píng)估 - 持續(xù)迭代”的閉環(huán)?;谶@個(gè)思路建議你接下來(lái)做以下增強(qiáng)把自己測(cè)試的真實(shí)業(yè)務(wù)數(shù)據(jù)替換掉樣例數(shù)據(jù)讓作品集更有業(yè)務(wù)說(shuō)服力嘗試接入一個(gè)國(guó)內(nèi)可用的模型服務(wù)比如 DeepSeek驗(yàn)證不同模型在 NL2SQL 場(chǎng)景下的表現(xiàn)差異增加 10 條真實(shí)測(cè)試用例記錄準(zhǔn)確率變化形成一份簡(jiǎn)短的效果評(píng)估報(bào)告把整個(gè)項(xiàng)目放進(jìn) GitHub順便把 README 寫(xiě)完整讓別人可以復(fù)現(xiàn)。當(dāng)你完成上面這些動(dòng)作之后這個(gè)作品集就不只是一個(gè)“AI 生成的 Demo”而是一個(gè)能證明你具備 AI 產(chǎn)品經(jīng)理核心能力的完整項(xiàng)目。9.3 作品集的長(zhǎng)期意義最后說(shuō)一點(diǎn)真心話(huà)。Vibe Coding 必然會(huì)繼續(xù)進(jìn)化模型能力也會(huì)越來(lái)越強(qiáng)也許未來(lái)會(huì)出現(xiàn)更輕量的方式直接構(gòu)建數(shù)據(jù)問(wèn)答系統(tǒng)。但無(wú)論工具怎么變作為 AI 產(chǎn)品經(jīng)理真正稀缺的能力始終是判斷什么場(chǎng)景值得做知道怎么把模糊想法拆成可落地的功能邊界能評(píng)估模型和產(chǎn)品的效果差距在哪里能推動(dòng)一個(gè) AI 功能從“能跑”走向“好用”。ChatBI 只是切入點(diǎn)。通過(guò)這個(gè)作品集你證明的不是“我會(huì)用 AI 寫(xiě)代碼”而是“我能用 AI 把一個(gè)產(chǎn)品想法變成可體驗(yàn)、可評(píng)估、可演進(jìn)的原型”。接下來(lái)就動(dòng)手打開(kāi) Cursor 或任意一個(gè) AI 編程工具把上面第 4 節(jié)的代碼結(jié)構(gòu)跑通。遇到問(wèn)題也不用怕報(bào)錯(cuò)信息直接貼給 AI改就完了。Vibe Coding 的樂(lè)趣恰恰就在這個(gè)“邊聊邊改、不斷逼近可用狀態(tài)”的過(guò)程里。如果這篇文章對(duì)你有幫助可以收藏備用。要是你想了解 ChatBI 更進(jìn)階的語(yǔ)義緩存實(shí)現(xiàn)或者想看更復(fù)雜的簡(jiǎn)歷案例可以在評(píng)論區(qū)留言我來(lái)安排。