资讯详情 Vibe Coding实战:用ChatBI打造AI产品经理高价值作品集
📅 2026/10/22 13:22:07
如果你正在准备 AI 产品经理的面试简历上写“熟练使用 ChatGPT”“会用 Cursor 写提示词”已经很难打动面试官了。这个门槛在过去一年里被快速抬高几乎每个候选人都能说两句 AI 工具的使用心得。真正决定区分度的是你有没有把一个 AI 项目从想法跑到落地并且能拿出可验证的成果。ChatBIChat-based Business Intelligence对话式智能分析是我认为最适合独立完成的 AI 产品作品集方向。它的业务价值清晰让业务人员用自然语言问数据而不是依赖数据分析师写 SQL。它的技术链路完整涉及 LLM 调用、NL2SQL、数据模型设计、结果校验和可视化。它还能同时展现产品经理的数据理解力、逻辑拆解力和工程协作力这是通用聊天机器人或 AI 写作工具很难达到的。这篇文章会围绕“如何用 Vibe Coding 的思路把一个 ChatBI 最小项目做出来并写进简历”展开。我会先讲清楚 Vibe Coding 对产品经理的真正含义再给出 ChatBI 的架构选型、数据模型设计、完整可复现代码、运行验证方式、常见坑位以及简历包装方法。你不需要已经有很强的编程背景但需要愿意按步骤把代码跑起来边跑边理解每一层设计。1. 为什么 ChatBI 是更适合写进简历的 AI 作品很多 AI 产品经理的作品集选择做智能客服、内容摘要、图片生成工具。这些方向不是不好而是同质化太严重并且很难体现“产品经理对数据的理解”。面试官看到十个智能客服作品很难分辨谁更强但一个完整的 ChatBI 项目能同时覆盖多种能力维度。ChatBI 背后至少牵扯五件事第一是自然语言理解用户的问题可能是模糊的、口语化的产品经理需要定义问题边界第二是数据建模你需要告诉模型表里有什么字段、字段之间怎么关联第三是提示词工程决定 LLM 生成的 SQL 是否准确第四是异常处理模型生成错误 SQL、幻觉列名、查询超时都必须被拦截第五是体验设计用户看到的结果不能只是一段 SQL而是图表和可解释的结论。从简历角度讲一个 ChatBI 作品能证明你不只是“会用 AI 工具”还能把一个业务问题翻译成技术方案。面试官看到这个项目至少有五个方向可以追问为什么选 NL2SQL 而不是 RAG表结构变复杂以后怎么办如何防止 SQL 幻觉怎么控制数据权限如何评估准确率这些问题你只要在项目里思考过回答起来就会从容得多。从投入产出比看ChatBI 也很适合个人做作品集。不需要大规模数据本地用 DuckDB 或 SQLite 就能承载模拟数据不需要 GPU调用现成大模型 API 即可不需要复杂前端Streamlit 几十行代码就能做出可交互界面。你可以用三五天跑通最小闭环再用一两周完善评测、权限和可视化细节。2. Vibe Coding 的真正门槛不是让 AI 一把梭“Vibe Coding”这个词现在很火直观理解是用自然语言描述需求让 AI 生成代码人来审查和修正。很多人以为 Vibe Coding 就是“想到什么说什么AI 全自动写完”这是一个很大的误解。真正能用于产品落地的 Vibe Coding核心是高频的反馈闭环你给 AI 一个指令运行验证结果发现问题再给更精确的指令如此循环。产品经理做 Vibe Coding最大的障碍不是不会写代码而是没有把需求拆成 AI 能执行的原子任务。举例来说需求“做一个销售问答系统”太笼统AI 不知道从哪里开始。需求“创建 orders 表字段包括 order_id、order_date、customer_id、product_id、category、amount、quantity并用五条模拟数据写入表”就是可执行指令。AI 擅长的是把明确的小任务快速实现而不是替你把模糊需求想清楚。第二个门槛是审查能力。AI 生成的代码可能会有 API 用法错误、表名笔误、逻辑漏判。你不需要成为资深工程师但至少要能读懂“这段代码在做什么”能复制报错信息能判断修改方向。比如 Streamlit 里 st.dataframe 和 st.bar_chart 的用法是否合理你要能通过运行结果验证而不是拿到代码就默认是正确的。第三个门槛是需求与代码的映射管理。Vibe Coding 过程中你很可能改很多轮。如果每次修改都靠口头记忆项目很快就会失控。我的习惯是维护一份 README 或 PRD 文档记录需求背景、数据定义、关键 Prompt 版本、已知问题和下一步计划。这份文档本身就是产品经理作品的一部分面试时可以直接展示“你是如何管理 AI 辅助开发过程的”。所以Vibe Coding 对产品经理的真正意义不是学会一门语言而是学会“用自然语言驱动工程实现”的新协作方式。你越能把需求讲清楚越能在运行结果中发现偏差作品质量就越接近一个真正的产品。3. ChatBI 的常见架构与方案选型做一个 ChatBI第一步不是写代码而是选架构。当前常见方案可以分成三类纯 RAG 问答、纯 NL2SQL、混合检索加 NL2SQL。它们各有适用场景没有绝对优劣。纯 RAG 方案把文档、报表拆成文本块存入向量数据库用户提问时先检索相关片段再把片段交给 LLM 生成回答。优点是适合非结构化数据比如超长的月报材料、会议纪要缺点是很难做精确的数值聚合用户问“华东区本月销售额环比增长多少”RAG 很难给出可信结果因为答案分散在文本里且可能是历史口径。纯 NL2SQL 方案让 LLM 直接根据表结构生成 SQL 并执行适合结构化数据比如订单表、用户表、库存表。它的优势是能精确计算劣势是表一多、字段一杂模型容易选错表或编造不存在的列名。缓解方式是在提示词里注入详细 schema、规则约束和少数示例。混合方案先通过向量检索或分类模型选出相关表再让 LLM 在候选表集合内生成 SQL。它适合几十张表以上的大型数仓能显著降低选表错误率但工程复杂度随之上升。对个人作品集来说我更推荐纯 NL2SQL 表选择约束的组合。你的数据规模控制在几张表以内把全部 schema 描述完整注入提示词同时让模型先判断“这个问题涉及哪些表”再基于这些表生成 SQL。这样既贴近生产环境中的主流做法又不会让代码过于庞杂。下面这张对比表可以帮助你快速做选择。方案适用场景优点缺点作品集推荐度纯 RAG非结构化文档问答实现简单检索灵活数值聚合不可靠低纯 NL2SQL少量结构化表精确计算结果可信表多后准确率下降高混合方案大规模数仓选表准确率高工程复杂度高中4. 环境准备与数据模型设计建议按本文思路准备一台本地开发环境即可不需要云服务器。你需要 Python 3.9 以上环境、一个 OpenAI 兼容 API 的 Key、以及 DuckDB、Streamlit、pandas、openai 这几个 Python 库。本文案例不绑定 OpenAI 官方版本而是使用 OpenAI 兼容接口所以只要设置 OPENAI_BASE_URL 指向国内可用的兼容服务商逻辑同理。这里不展开讨论任何网络连接问题只做接口配置说明。先创建项目目录并准备好依赖mkdir chatbi-demo cd chatbi-demo pip install duckdb streamlit pandas openai接下来设计数据模型。ChatBI 里数据模型的质量直接决定 SQL 生成的准确率。模型不能只让 LLM 看到英文表名还需要给每张表、每个字段补充业务描述。你可以建立三张表orders 订单事实表、products 商品表、customers 客户表。-- 文件路径chatbi-demo/setup_data.sql CREATE TABLE orders ( order_id VARCHAR PRIMARY KEY, order_date DATE, customer_id VARCHAR, product_id VARCHAR, category VARCHAR, amount DECIMAL(10, 2), quantity INT ); CREATE TABLE products ( product_id VARCHAR PRIMARY KEY, product_name VARCHAR, unit_price DECIMAL(10, 2) ); CREATE TABLE customers ( customer_id VARCHAR PRIMARY KEY, customer_name VARCHAR, region VARCHAR, channel VARCHAR ); INSERT INTO products VALUES (P001, 智能手机, 5999.00), (P002, 笔记本电脑, 8999.00), (P003, 蓝牙耳机, 499.00); INSERT INTO customers VALUES (C001, 华东零售客户, 华东, 线下), (C002, 华北企业客户, 华北, 线上); INSERT INTO orders VALUES (O001, DATE 2025-06-01, C001, P001, 数码, 5999.00, 1), (O002, DATE 2025-06-03, C002, P002, 数码, 8999.00, 1), (O003, DATE 2025-06-10, C001, P003, 数码, 499.00, 2), (O004, DATE 2025-07-02, C002, P001, 数码, 11998.00, 2);为什么我要在表设计里强调业务描述因为 LLM 对英文列名的语义理解是有限的。比如 category 字段可能被理解成“类目”但你希望它知道这是“商品一级类目”。所以下一步要写 schema 描述文件把字段含义、单位、聚合规则明确告诉模型。{ tables: [ { name: orders, description: 订单事实表每一行是一个订单的汇总明细包含客户、商品、类目、金额、数量, columns: [ { name: order_id, description: 订单编号全局唯一 }, { name: order_date, description: 下单日期格式为 YYYY-MM-DD }, { name: customer_id, description: 下单客户ID关联 customers 表 }, { name: product_id, description: 商品ID关联 products 表 }, { name: category, description: 商品一级类目例如数码、家电、服饰 }, { name: amount, description: 订单金额单位人民币元 }, { name: quantity, description: 购买数量整数 } ] }, { name: products, description: 商品维度表记录商品名称和单价, columns: [ { name: product_id, description: 商品ID关联 orders 表 }, { name: product_name, description: 商品名称 }, { name: unit_price, description: 商品单价单位人民币元 } ] }, { name: customers, description: 客户维度表记录客户名称、地区和渠道, columns: [ { name: customer_id, description: 客户ID关联 orders 表 }, { name: customer_name, description: 客户名称 }, { name: region, description: 客户所在区域 }, { name: channel, description: 客户来源渠道线上或线下 } ] } ], rules: [ 按月统计时使用 strftime(order_date, %Y-%m), 金额聚合使用 SUM(amount)数量聚合使用 SUM(quantity), 涉及上月时以当前系统时间的前一个月为准, 不要在 SQL 中引用 schema 里不存在的列, 如果问题与销售数据无关输出 SELECT NULL ] }这一步对产品经理尤其重要。你相当于在设计一个小型数据字典面试时可以说明“我如何把业务口径转化为模型可理解的提示词上下文”。然后在同一目录下执行建表和数据导入duckdb chatbi.db setup_data.sql运行完成后可以用duckdb chatbi.db SELECT * FROM orders;验证数据是否写入成功。后续 Python 脚本会直接连接 chatbi.db。5. 核心流程拆解从用户问题到图表一个 ChatBI 请求从输入到展示会经过五个环节。理解这五个环节等于理解了这类产品的通用架构。第一步是用户提问。用户说“上个月各品类的销售金额是多少”这句话本身是模糊的。“上个月”到底指自然月还是最近三十天产品经理要在规则里给出默认口径避免模型自行猜测。第二步是表选择与意图理解。在少数几张表的场景下可以让 LLM 直接基于全部 schema 判断涉及哪些表。如果以后扩展到几十张表就要先加一个检索步骤把候选表缩小到三五张否则上下文过长会严重降低生成质量。第三步是生成 SQL。LLM 根据 schema 描述、业务规则和用户问题生成 DuckDB SQL。这里的关键参数是 temperature建议设置为 0让模型尽量保持确定性。不要在这里允许多次随机尝试否则同一问题可能生成不同 SQL用户无法建立信任。第四步是 SQL 校验。这个环节最容易被人忽略但却是生产环境最重要的安全边界。你需要检查 SQL 是否存在危险关键字、是否引用了不存在的表或列、是否会超出权限。即使是个人作品我也建议至少做一个“是否 SELECT NULL”的判断并把生成的 SQL 原样展示给用户。第五步是执行与可视化。执行查询得到 DataFrame 后根据列类型选择图表。日期加数值可以画趋势线类目加数值可以画柱状图地区加数值可以画地图。基础 Demo 可以先统一用柱状图但产品经理应该想清楚“什么样的图表适合什么样的回答”。6. 完整代码实现ChatBI 最小可用版本这一节我给出一个可运行的最小实现。代码分两个文件第一个是 sql_agent.py负责加载 schema、调用 LLM 生成 SQL、清洗 SQL 和执行查询第二个是 app.py负责用 Streamlit 搭建交互界面。版本细节以你的实际环境为准本文重点是通用思路。# 文件路径chatbi-demo/sql_agent.py import json import os import re import duckdb from openai import OpenAI client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL, https://api.openai.com/v1), ) def load_schema_text(path: str schema.json) - str: with open(path, r, encodingutf-8) as f: schema json.load(f) lines [] for table in schema[tables]: lines.append(f表名: {table[name]} - {table[description]}) for col in table[columns]: lines.append(f {col[name]}: {col[description]}) lines.append(业务规则:) for rule in schema.get(rules, []): lines.append(f- {rule}) return \n.join(lines) def build_prompt(question: str) - str: schema_text load_schema_text() prompt f 你是一个数据分析师负责把中文业务问题转换为 DuckDB SQL。 数据库表结构说明如下 {schema_text} 用户问题{question} 要求 1. 只输出可执行的 DuckDB SQL不要任何解释。 2. 如果问题与这些表无关输出 SELECT NULL; return prompt def clean_sql(text: str) - str: text text.strip() code_block re.search(rsql\s*(.*?)\s*, text, re.S) if code_block: return code_block.group(1) if text.startswith(sql): text text[len(sql):].strip() if text.startswith(): text text[len():].strip() return text def generate_sql(question: str) - str: resp client.chat.completions.create( modelos.getenv(MODEL_NAME, gpt-4o-mini), messages[ {role: system, content: 你是 DuckDB SQL 专家只会输出 SQL。}, {role: user, content: build_prompt(question)}, ], temperature0, ) raw_sql resp.choices[0].message.content return clean_sql(raw_sql) def run_sql(sql: str) - list[dict]: if not sql or SELECT NULL in sql.upper(): return [] with duckdb.connect(chatbi.db) as conn: cur conn.execute(sql) columns [desc[0] for desc in cur.description] rows cur.fetchall() return [dict(zip(columns, row)) for row in rows]这个文件的关键逻辑是把 schema.json 转成纯文本上下文拼进 Prompt调用大模型拿到 SQL对返回内容做清洗去掉 Markdown 代码块标记执行查询把结果转成字典列表。你可能会问为什么不在代码里硬编码表结构因为对产品经理来说以后调整业务口径只需要改 JSON改模型交互成本最低。这是产品思维在工程实现里的体现。# 文件路径chatbi-demo/app.py import pandas as pd import streamlit as st from sql_agent import generate_sql, run_sql st.set_page_config(page_titleChatBI 最小实现, layoutwide) st.title(ChatBI用中文问销售数据) question st.text_input( 请输入问题, placeholder例如上个月各品类的销售金额分别是多少, ) if st.button(生成 SQL 并查询): if not question: st.warning(请先输入问题。) else: with st.spinner(正在生成 SQL...): sql generate_sql(question) st.subheader(生成的 SQL) st.code(sql, languagesql) data run_sql(sql) if not data: st.info(没有查询结果。请确认问题是否与销售数据相关或检查 SQL 是否正确。) else: df pd.DataFrame(data) st.subheader(查询结果) st.dataframe(df) numeric_cols df.select_dtypes(include[number]).columns.tolist() if numeric_cols: st.subheader(可视化) chart_df df.set_index(df.columns[0])[numeric_cols[0]] st.bar_chart(chart_df)Streamlit 界面的交互逻辑不算复杂。用户输入问题点击按钮先展示生成的 SQL再展示表格和柱状图。把 SQL 展示出来是对用户非常负责的做法。因为 ChatBI 与普通聊天机器人不同用户需要在关键决策场景里信任结果可解释性是产品设计中必须考虑的一环。运行命令如下export OPENAI_API_KEY你的API Key export OPENAI_BASE_URLhttps://api.openai.com/v1 export MODEL_NAMEgpt-4o-mini python -m streamlit run app.py在 Windows PowerShell 下环境变量用$env:OPENAI_API_KEY...方式设置。跑起来以后浏览器会自动打开 Streamlit 页面。输入“上个月各品类的销售金额分别是多少”你就能看到 SQL、数据表和一张某品类与金额的柱状图。7. 运行结果与效果验证很多初学者做 ChatBI 跑通以后只验证“界面能不能打开”就认为项目完成了。这是远远不够的。产品经理需要定义一组验证问题集用同一批问题反复测试记录成功率和失败原因。我建议你至少准备 10 个覆盖不同场景的测试问题。按习惯我会把它们整理成这样的验证清单场景示例问题期望结果验证重点简单聚合一共有多少订单SELECT COUNT(*)基础查询能力单表分组各品类的销售金额按 category 分组 SUM(amount)分组聚合能力多表关联华东客户买了哪些商品JOIN 两张表表关联理解时间筛选上个月的销售金额使用 strftime 过滤月份时间口径理解指标计算每笔订单的平均金额AVG(amount)聚合函数理解排序查询销量最高的前三个商品ORDER BY LIMIT排序限制能力无效问题今天天气怎么样SELECT NULL边界处理能力执行完这些测试你需要记录三类数据SQL 完全正确的问题数量、SQL 可执行但结果错误的问题数量、完全无法执行或模型乱答的问题数量。这个评测结果就是简历上最有说服力的指标。但请记住不要编造“准确率 95%”这样的数字。建议以你自己测试的真实结果为准写下评测方法和改进过程。如果发现结果不对第一步是看生成的 SQL 是否符合业务口径而不是直接怀疑模型能力。比如“上个月各品类的销售金额”如果模型没有按品类分组而是按订单明细查询那么问题出在规则描述不够明确。你需要在 schema.json 的 rules 中补充“涉及销售金额按类目统计时必须使用 SUM(amount) GROUP BY category”。这种通过调整 Prompt 和数据字典来修正行为的过程正是 ChatBI 产品经理的核心工作。8. 常见问题与排查思路从我的经验看ChatBI 的最小 Demo 跑通不难但深入下去会遇到各种问题。这里整理了一张排查表覆盖最常出现的几个故障点。问题现象可能原因排查方式解决方案模型输出了 SQL 但执行报错引用了不存在列名查看 SQL 和报错信息补全 schema 描述增加列名校验返回内容包含大量解释文字未在提示词中限制输出格式查看原始返回值增加“只输出 SQL”并要求抽取代码块时间过滤结果为空日期格式或月份口径不一致用 SQL 手动查询数据统一 strftime 格式明确“上月”定义相同问题每次 SQL 不同temperature 设置过高检查调用参数将 temperature 设为 0多表数据对不上JOIN 关联字段理解错误查看模型选择的关联列在 schema 中明确外键关系用户问题包含负面词却返回全部数据提示词缺少边界说明构造边界测试增加“与销售数据无关输出 SELECT NULL”查询响应太慢原始数据量大、缺少聚合模型分析执行计划构建预聚合表或限制查询范围再具体展开两个高频问题。第一个是高幻觉问题。模型在生成 SQL 时可能生成一个看起来合理但实际上不存在的列名比如把 amount_2025 这种不存在的字段造出来。缓解方法是两层校验结构校验和规则校验。结构校验检查 SQL 里出现的列名是否都在 schema 中规则校验判断聚合函数、过滤条件是否符合业务口径。个人作品至少要做第一层可以把 schema 中的所有列名拼成一个集合用正则抽取 SQL 中的字段名做比对。第二个是隐私与权限问题。如果给业务用户上线不能让他们通过 ChatBI 查询任意敏感字段或执行任意 SQL。产品经理要在架构里加入行级权限和列级权限控制最简单的方式是给每条 SQL 注入用户维度的过滤条件比如强制加上WHERE region 华东而不是把整表内容暴露给所有人。在本地 Demo 中可能不需要完整实现但简历里应该体现这个思考。9. 简历包装与生产环境最佳实践项目做完以后最重要的是把它包装成面试官能快速理解、能深入提问的简历条目。这里有一个最常见的误区只写“使用 Python 和 ChatGPT 实现了一个 ChatBI 系统”这跟没写差别不大。更好的写法是突出业务问题、方案架构、个人职责和量化效果。以本文的 Demo 为例可以这样组织项目名称销售数据智能问答助手ChatBI 角色独立产品负责人 技术栈Python、DuckDB、Streamlit、OpenAI 兼容 API、Prompt Engineering 项目内容设计订单、商品、客户三张维度和事实表构建中文业务数据字典通过 NL2SQL 方案将中文提问转换为 DuckDB SQL完成查询与图表展示建立 10 条业务规则约束和一套验证问题集覆盖聚合、关联、时间筛选、边界处理等场景采用 SQL 前置展示与结果可解释设计提升用户对 AI 生成结果的信任。面试前还要准备好三个追问方向的第一层回答。为什么用 NL2SQL 而不是 RAG你可以说数据是结构化的RAG 无法精确聚合NL2SQL 能保证计算结果准确。表变多了怎么办你可以说先通过检索或 LLM 分类选出候选表再生成 SQL避免上下文过长。如何防止模型编造字段你可以说用 schema 规则约束加上列名校验层并在前端展示 SQL 方便人工复核。这些回答不需要完美但必须体现你实际踩过坑、想过方案。如果要把这个 Demo 往生产环境推进有几个工程习惯越早养成越好。第一所有数据库操作使用只读账号防止 ChatBI 的 SQL 被恶意利用第二记录每次提问、生成的 SQL、执行时间和用户反馈形成评测日志这是持续优化 Prompt 的依据第三重要查询结果加入缓存同样的问题在短时间内重复提问直接命中缓存降低 API 成本和响应时间第四Prompt 和 schema 也要做版本管理不要直接在代码里无记录地改否则你不知道哪个规则的调整造成了结果变化。最后提醒一点ChatBI 的深度其实远超一个 Demo。你可以继续研究 TableAgent 的工作方式、研究 NL2SQL 在 Text-to-SQL 榜单上的评测方法、研究如何把数据权限和租户隔离设计进系统。把这几层想明白你就不再是“用过 AI 工具的产品经理”而是“能把 AI 能力封装成产品的产品经理”。这恰恰是 AI 产品经理作品集最需要证明的东西。建议你按这篇文章先把最小项目跑通再用自己的业务理解去填充评测、权限和可解释性这几个章节那才是你简历里真正值钱的部分。