news 2026/9/17 22:02:04

LLM Zoomcamp 监控实战:在 Streamlit 仪表盘上可视化用户反馈与判官相关性评分

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LLM Zoomcamp 监控实战:在 Streamlit 仪表盘上可视化用户反馈与判官相关性评分

LLM Zoomcamp 监控实战:在 Streamlit 仪表盘上可视化用户反馈与判官相关性评分

【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 👇🏼项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp

反馈仪表盘是 LLM Zoomcamp 2026 期监控模块(Module 5)的核心一课:前几课我们已经通过+1/-1按钮收集了用户对回答的赞踩,又用 LLM 判官为每条回答自动打上相关性标签,但这两类信号至今还只躺在 PostgreSQL 的feedback表里,没有任何可视化。本文讲解如何把这两类反馈接到第 07 课搭建的 Streamlit 仪表盘上,让"成本、延迟、质量"三组指标同屏展示,并说明为什么下一步需要合成数据来让图表"活"起来。读完你将掌握:在db_query.py中编写反馈聚合查询、在dashboard.py中渲染相关性分布柱状图与赞踩计数指标,以及完整的数据链路(写入 → 查询 → 展示)。

两类反馈的来龙去脉

到第 09 课为止,系统中已经存在两种截然不同的反馈来源,它们被统一写入同一张feedback表,靠source列区分:

  • 用户反馈(source = 'user':第 08 课在聊天应用中为每条回答下方添加了+1/-1按钮,点击后通过 db_feedback.py 的save_feedback(conversation_id, "user", score=1)写入score字段(+1 代表赞,-1 代表踩);
  • 判官反馈(source = 'judge':第 09 课内置了 LLM 判官(judge.py),每次回答后用结构化输出返回RELEVANT/PARTLY_RELEVANT/NON_RELEVANT三档标签及解释,写入relevanceexplanation字段。

这张表的完整结构定义在 db_init.py 的init_feedback()中:

CREATE TABLE feedback ( id SERIAL PRIMARY KEY, conversation_id INTEGER REFERENCES conversations(id), source TEXT NOT NULL, relevance TEXT, explanation TEXT, score INTEGER, timestamp TIMESTAMP WITH TIME ZONE NOT NULL )

从源码结构看,这一设计刻意让两类反馈共用一张表:用户给出的是二元极性(赞/踩),判官给出的是三档相关性标签,而conversation_id外键把每条反馈精确绑定到某一次对话。这样一来,仪表盘既能单独统计两类信号,未来也能把"用户说好"与"判官说相关"做交叉比对。

问题在于:数据一直在写,却没有任何地方能看到它们。第 07 课的仪表盘只展示了总对话数、平均响应时间、总成本、平均 token 数以及成本和延迟的时间序列,反馈数据对运维人员完全不可见。本课要做的就是把这两个维度补上。

第一步:给 db_query.py 添加反馈聚合查询

所有仪表盘数据都经由 db_query.py 统一封装数据库访问。该文件已有的get_conversations()(拉取最近对话)和get_stats()(聚合统计)沿用了统一的"获取连接 → 执行 SQL → 关闭连接"模式,其中get_db_connection()来自db_init.py,通过环境变量POSTGRES_HOSTPOSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORD配置连接,默认值分别为localhostcourse_assistantuserpassword

现在按同样的模式添加两个反馈查询函数。

判官相关性分布

get_relevance_stats()relevance标签分组计数,只统计source = 'judge'的行:

def get_relevance_stats(): conn = get_db_connection() try: with conn.cursor() as cur: cur.execute(""" SELECT relevance, COUNT(*) FROM feedback WHERE source = 'judge' GROUP BY relevance """) rows = cur.fetchall() finally: conn.close() return dict(rows)

返回的是一个形如{"RELEVANT": 12, "PARTLY_RELEVANT": 5, "NON_RELEVANT": 3}的字典——键是相关性标签,值是出现次数。这个结构恰好能直接喂给 Streamlit 的st.bar_chart

用户赞踩统计

get_user_feedback_stats()用两个条件聚合分别统计赞与踩的数量,只统计source = 'user'的行:

def get_user_feedback_stats(): conn = get_db_connection() try: with conn.cursor() as cur: cur.execute(""" SELECT SUM(CASE WHEN score > 0 THEN 1 ELSE 0 END), SUM(CASE WHEN score < 0 THEN 1 ELSE 0 END) FROM feedback WHERE source = 'user' """) row = cur.fetchone() finally: conn.close() return row

返回值是一个二元组(thumbs_up, thumbs_down)。注意这里的语义约定:score > 0即 +1(赞),score < 0即 -1(踩),这一约定与第 08 课save_feedback(conversation_id, "user", score=1)的调用方式一一对应,字段级含义可回看 08-user-feedback.md。

两个函数都严格遵循了finally: conn.close()的写法,确保无论查询成功与否连接都会被释放——这是本模块所有数据库访问代码的通用防御性模式。

第二步:把反馈面板接入 dashboard.py

接下来修改 dashboard.py。该文件当前结构为:顶部四列metric展示汇总指标,中部用st.line_chart绘制成本与响应时间的时间序列,底部用纯文本列出最近对话(prompt[:80]answer[:200]截断)。我们要在保留这些内容的基础上追加反馈面板。

更新 import

把两个新函数加进导入语句:

from db_query import get_conversations, get_stats, get_relevance_stats, get_user_feedback_stats

判官相关性分布

在页面合适位置(例如成本/延迟图表之后)添加:

st.subheader("Judge relevance") relevance = get_relevance_stats() st.bar_chart(relevance)

st.bar_chart会把字典的键作为横轴类别、值作为柱高,三档相关性标签的分布一眼可见。当判官给出的NON_RELEVANT占比升高时,通常意味着检索质量或提示词出了问题——这正是自动质量信号的价值:不需要等用户点击,每条回答都会产生一个可观测的质量标签

用户反馈

紧随其后添加:

st.subheader("User feedback") thumbs_up, thumbs_down = get_user_feedback_stats() col1, col2 = st.columns(2) col1.metric("Thumbs up", int(thumbs_up or 0)) col2.metric("Thumbs down", int(thumbs_down or 0))

thumbs_up or 0的写法是为了防御SUM在空表上返回None(没有匹配行时聚合结果为 NULL),int()则把 SQL 返回的数值转成 Streamlit 指标可接受的原生类型。两个metric并排展示赞踩总数,语义与 ChatGPT 等产品中的反馈计数一致。

运行仪表盘

由于聊天应用已经占用了 8501 端口(对应第 03 课),仪表盘需要用独立端口启动:

uv run streamlit run dashboard.py --server.port 8502

运行前提是本模块前面课程已完成:PostgreSQL 已通过 Docker 启动、uv run python db_init.py已初始化conversationsfeedback表、generate_data.py或真实对话已产生数据。若尚未安装依赖,可参考 Makefile 中的项目定义(使用uv管理 Python 环境与依赖)。

至此,仪表盘呈现了四个维度的信息:成本(总成本、成本时间序列)、速度(平均响应时间、响应时间序列)、自动质量(判官相关性分布)与人工质量(用户赞踩计数)。从第 07 课开始,我们一直刻意把仪表盘保持得足够简单——st.subheader+st.bar_chart+st.metric就完成了全部工作,没有任何多余装饰,这是为了让你能自上而下读懂每一行代码。

第三步:面对空图表的现实——为什么需要合成数据

把面板加上之后,立刻会撞上一个实际问题:如果只有三五条真实对话,这些图表几乎是空的。用户点赞可能只有 1~2 次,相关性分布也撑不起有意义的柱状图。原因很直接:真实流量需要真实用户,而课程演示环境下不会有人持续提问。

解决思路不是等用户,而是主动造数据。第 11 课(11-synthetic-data.md)提供了一个 generate_data.py 脚本:每秒钟向 PostgreSQL 插入一条带反馈的模拟对话,循环不停,直到 Ctrl+C 终止。

uv run python generate_data.py

该脚本的generate_one()揭示了"反馈如何被填充"的完整逻辑,可与本课的查询逻辑对照理解:

  • 从 5 个预置问题与 5 个预置回答中随机组合,用fake_record()生成一条带随机 token 数、响应时间(0.5~5.0 秒)与成本(0.0001~0.01 美元)的LLMCallRecord,经save_conversation()入库;
  • 以 70% 概率写入一条source = 'judge'的反馈,relevanceRELEVANT/PARTLY_RELEVANT/NON_RELEVANT三档随机取;
  • 以 50% 概率写入一条source = 'user'的反馈,分数从[1, 1, 1, 1, -1]中随机取——刻意让赞远多于踩,模拟"多数用户对回答满意"的真实分布。

这个闭环设计正好呼应本课的主题:先把反馈写进feedback表(第 08、09 课),再把它查出来画成图(本课),最后用合成数据把图填满(第 11 课),为下一课迁移到 Grafana 提供有实际体积的数据基础。

小结与源码路径

本课完成了一次完整的"反馈可视化"闭环:

  1. 写入侧:用户赞踩与判官相关性共用feedback表(db_init.py),由 db_feedback.py 的save_feedback()统一写入;
  2. 查询侧:在 db_query.py 新增get_relevance_stats()get_user_feedback_stats()两个聚合查询;
  3. 展示侧:在 dashboard.py 增加"Judge relevance"柱状图与"User feedback"双指标,与既有的成本、延迟面板并列;
  4. 数据供给:用 generate_data.py 持续注入合成数据,让仪表盘具备可观察的体量。

至此,"成本 + 速度 + 质量"三位一体的在线监控视图就齐了。下一步(第 12 课起)将把同样的数据接到 Grafana,用 SQL 查询构建更强大的实时面板与告警能力。如果你想深入阅读每一环的完整实现,本模块的课程笔记顺序为 07-streamlit-dashboard.md(基础面板)→ 08-user-feedback.md(用户反馈采集)→ 09-built-in-judge.md(判官实现)→ 10-feedback-dashboard.md(本课)→ 11-synthetic-data.md(合成数据)。

【免费下载链接】llm-zoomcampLLM Zoomcamp - a free online course about real-life applications of LLMs. In 10 weeks you will learn how to build an AI system that answers questions about your knowledge base. Register here 👇🏼项目地址: https://gitcode.com/GitHub_Trending/ll/llm-zoomcamp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 22:01:21

VS2022缺少MFC模板与控件无法添加事件的解决方法

刚装完 VS2022&#xff0c;兴冲冲打开新建项目窗口&#xff0c;搜索框里输入 MFC&#xff0c;结果一个模板都不出来&#xff1b;或者好不容易建了个对话框工程&#xff0c;从工具箱拖了按钮、编辑框&#xff0c;右键想“添加事件处理程序”&#xff0c;菜单却是灰的。这种场景我…

作者头像 李华
网站建设 2026/9/17 21:59:32

企业训考一体化工具推荐:支持在线考试的培训系统汇总

数字化转型背景下&#xff0c;企业内部员工培训、技能考核、岗前测评的需求持续升级&#xff0c;传统线下集中培训、纸质考试模式效率低下、数据难以留存&#xff0c;无法适配现代企业常态化人才培养需求。训考一体化系统凭借线上培训、智能出题、自动考核、数据复盘的全链路能…

作者头像 李华
网站建设 2026/9/17 21:59:13

Excel工作表保护密码破解:VBA脚本与XML清理法详解

简介&#xff1a;这是一份面向办公人员与数据处理初学者的Excel工作表保护破解实操文档&#xff0c;解决因忘记密码或他人设置锁定而无法编辑、查看工作表内容的常见问题。文档首先讲解工作表保护的标准设置方法&#xff0c;包括锁定单元格与保护工作表的操作路径&#xff1b;随…

作者头像 李华