2026年1月19日这天,我给自己定了一个小目标:不刷短视频,不翻收藏夹,用一整块时间把最近囤着没消化的几个技术点一次性理清楚。结果从早上十点坐到晚上八点,还真顺藤摸瓜摸出了一条完整的链路,从AI生成、结果校验,到日志采集、数据可视化,四段内容居然能串成一个小闭环。这篇学习笔记就按当时的推进顺序来写,该给的代码、参数、踩坑点都放进去,希望能给同样在自学路上的朋友一点参考。
1. 今天为什么学这些:从临时想法到一个小闭环
这天的学习任务其实是一周前就攒下的,主要想解决三件事。第一,我在做一个给文章自动写摘要的小工具,但生成出来的内容经常“看起来通顺,实际跑偏”,我需要搞清楚提示词到底该怎么调才稳定。第二,工具跑起来之后,每天生成几百条结果,但没有任何机制能告诉我哪条是垃圾,哪条能直接用。第三,我想把整个工具的运行情况做成一个简单的可视化看板,不想每次都登录服务器敲命令查日志。
原本打算一个一个处理,结果把它们放在一起想的时候才发现,这三件事本来就是一条链路:生成结果 → 质量校验 → 数据采集 → 数据展示。于是这一天我干脆按这个顺序,把每个环节都走了一遍。
这条链路里面有不少通用的设计思路,比如提示词的权重分配、校验器的分层逻辑、日志格式的规范化、看板指标的选择。整篇笔记都会围绕这些展开,并且每一步都会写清楚“当时为什么这么做,遇到了什么问题,最后的参数是怎么定下来的”。
如果你也是那种边学边做、喜欢把零散知识点串成系统的人,这篇笔记应该能给你一些启发。尤其是AI生成类工具的同学,第三部分关于生成结果校验的写法,建议多看两遍。
2. 写AI摘要生成器:提示词权重最容易被忽视
上午的时间基本都耗在调这个摘要生成器上。先说结论:同样的模型,同样的输入,提示词写法不同,输出质量能差出一大截。
2.1 第一版提示词为什么失败
这是我最初写的提示词,当时觉得很完美:背景、任务、要求、格式全都说清楚了。
提示词第一版: 你是一个专业的文章摘要助手。 请阅读下面的文章,生成一段摘要。 要求: 1. 摘要不超过200字 2. 保留文章的核心观点 3. 语言简洁通顺实测下来的问题很明显:生成的摘要经常抓错重点。比如一篇讲数据库索引原理的文章,摘要里却花了一半篇幅讲B+树的历史背景,核心的“最左前缀匹配规则”反而没提。
后来我仔细对比了多组实验结果才意识到,问题出在每个要求的权重没有被显式拉开。所有要求都是同级的“要求”,模型无法判断哪一条最重要。当文章内容比较复杂、信息量大的时候,模型就只能“平均用力”,结果哪头都抓不好。
2.2 用权重词拉开优先级
我参考了一些公开的最佳实践,把提示词改成了分优先级的结构。用“最高优先级”“次之”“不得”这类词,把要求排出主次。
提示词第二版(精简示例): 你是一个擅长信息抽取的资深编辑。 请为下面的文章生成摘要,遵循以下优先级: - 最高优先级:摘要必须准确覆盖文章的核心结论,以及支撑结论的2-3个关键依据。 - 次之:确保数据、名称、时间等信息准确无误,不得编造。 - 再次:控制篇幅在200字之内,语言通顺。 - 不得:添加任何正文未提及的主观评价。 文章内容如下: {文章内容}这么一改,效果立竿见影。跑了几十条测试,摘要的核心命中率有明显提升,至少不会再把背景信息当主体。
2.3 温度参数和重复调用
除了提示词,还有个容易被忽略的细节:生成参数。尤其是temperature(温度系数)这个值,它控制模型输出随机性的大小。值越大,生成内容越多样;值越小,输出越稳定。
做摘要这类抽取式任务,我会把temperature调到0.2到0.4之间,宁可损失一点“措辞多样性”,也要保证每次生成的内容都贴题。
还有一个更朴素的技巧:对同一条输入跑2到3次,然后从结果里挑最好的一条。这里有个细节值得说:不是让你直接用第一次结果,也不是让你把多次结果合并,而是用另一套规则去打分,比如“是否提到核心关键词”“是否有明显重复”“长度是否合理”,分高者胜。这样做好处很直接——成本翻两三倍,但交付质量能明显稳定下来,适合后端异步生成的场景。
3. 给生成结果兜底:Monologue组件的三点核心设计
下午的精力集中在怎么给生成结果加一道“质检关”。我给自己写的这套东西取了个代号叫Monologue——中文可以理解为“生成内容的自我审视机制”。它要做的事情很简单:在生成器输出之后,再跑一个独立的校验,判断这段内容能不能用。
3.1 稳定性分层的思想
开始动手之前,我给自己定了一条原则:生成结果一定会有不稳定的时候,这很正常,关键是当不稳定结果出现时,系统要能发现它、标记它,而不是让它在下游悄无声息地被消费。
所以Monologue的分层是这样的:
- 第一层,格式校验。比如要求摘要必须大于50字,不能超过300字,不能含有空行。这些都是硬规则,不满足直接判失败。
- 第二层,语义贴题检测。把文章里提取出来的核心关键词列表,拿去和生成的摘要做比对,看摘要里到底覆盖了几个。
- 第三层,交叉确认。用两种不同参数跑两次,把两次结果做相似度计算,如果相似度极低,就说明生成结果本身就很不稳定,需要标记。
三层互补,成本可控,基本覆盖了我遇到过的所有坏结果类型。
3.2 摘要覆盖率计算的两种落地方式
“覆盖率”这个词说起来很抽象,我实际落地时用了两种方式。
方式A叫关键词覆盖法。先从原文里用词频加TF-IDF找出前10个关键词,然后统计生成的摘要里出现了几个。如果覆盖率低于60%,判为低质量。这个方法实现简单,但关键词重复出现在摘要里也算命中,所以存在一点刷字数的漏洞。
方式B叫语义相似度法。把原文和摘要都转成向量,计算余弦相似度。优点是不怕同义改写,缺点是计算成本高一点,而且有时候原文太长,向量表示会稀释关键信息。
我最终把两种方法结合了一下:先跑方式A,低于阈值直接判负;高于阈值再跑方式B,二次确认。实测下来误杀率能控制在很低的水平。
3.3 失败后的回退策略
校验通过的内容直接走下游,那没通过的呢?我留了两条退路。
第一条退路是重试。带着“上次生成无效,请重写”的提示词再跑一次,下一次的成功率通常会高一些。因为模型在失败提示里能看到自己上一次的输出,能针对性地修正。
第二条退路是降级。连续重试两次都失败的话,就不再硬生成摘要,而是直接把原文的第一段和结尾段拼接起来,做一个“不负责任但至少不开天窗”的兜底。这个结果是明确标注了状态的,下游知道它是低置信度内容。
这里我想强调的是,校验模块一定要独立于生成模块之外,不要写在同一个类里面。因为校验逻辑会被反复修改,你不想因为改校验规则导致生成代码也跟着重新部署。独立之后,规则更新和重放测试都方便多了。
4. 采集侧的日子:nginx日志清洗为结构化记录
做完了生成和校验,其实这个工具已经能用了。但我还想知道它到底跑得怎么样,于是把目光转向了部署环境里的nginx日志。这一步的目标很简单:把散落在日志文件里的原始记录,变成能直接入数据库的结构化数据。
4.1 一条完整访问日志的字段拆解
nginx默认日志格式大概长这样:
127.0.0.1 - - [19/Jan/2026:09:15:23 +0800] "GET /api/summary?text_id=1024 HTTP/1.1" 200 532 "curl/8.5.0"一条一行,里面藏着不少信息。按空格拆开来看,大致是:
| 字段位置 | 内容示例 | 含义 |
|---|---|---|
| 第1段 | 127.0.0.1 | 客户端IP |
| 第4段 | [19/Jan/2026:09:15:23 +0800] | 请求时间 |
| 第5段 | "GET /api/summary?text_id=1024 HTTP/1.1" | 请求方法、路径、协议 |
| 第6段 | 200 | 状态码 |
| 第7段 | 532 | 响应字节数 |
| 第8段 | "curl/8.5.0" | User-Agent |
单条看起来不复杂,问题是生产环境里每天几万条日志,再加上接口里塞的各类参数,不做清洗根本没法用。
4.2 用awk写第一版清洗脚本
清洗的第一步,是在服务端做粗糙的格式规整。我用awk写了一个简短的脚本,把时间、IP、状态码、请求路径、耗时这五个字段提取出来:
awk '{print $1, $4, $6, $7, $9}' /var/log/nginx/access.log但马上发现问题:$4是带方括号的时间,$7里混杂了请求行和协议版本,直接输出会很脏。于是加了一步gsub和match处理,把方括号和引号剥掉。这一步在命令行里能直接出结果,适合快速验证。
等到确认字段能准确提取了,我就把处理逻辑整理成了一个定时任务,每小时跑一次,把清洗结果追加写入本地的记录文件。后续再用LogStash或者自研脚本把记录文件同步到分析库。先用脚本规整,再谈架构,算是踩过不少坑后得到的实在经验。
4.3 增加字段:识别请求来源和安全视角
清洗的最终目的不只是统计访问量。我还想在数据里看到两类信息:请求是从哪里来的,以及有没有异常特征。
为此我改写了nginx日志格式,在默认字段后面增加了request_time和upstream_response_time,方便分析接口慢在哪一段。另外还加了一个自定义字段,用于标记请求是否携带了有效的业务方标识。
顺带提一句,这段时间我注意到日志里出现了一些比较规律的扫描特征,比如短时间连续请求不存在的路径、状态码大量404。后来我写了个简单规则,把这类来源的日志单独标记出来,方便后续做安全层面的观察。做日志采集的同学,建议从一开始就把这类安全视角的字段考虑进去,不要等出了问题再翻日志补数据。
5. 可视化收尾:用Dash搭一块三类指标看板
清洗完成的日志数据已经入了库,最后一步就是把它展示出来。我选的是Dash——Python生态里做数据看板非常顺手的框架,好处是纯Python写逻辑,不用前端知识也能出交互式图表。
5.1 看板指标选什么
看板不能什么都放,放太多等于没放。我给自己定了三类核心指标:
- 趋势类:每小时的请求量折线图,能看出高峰低谷。
- 质量类:摘要生成成功率和校验通过率的双折线,这是整个工具的命门。
- 异常类:状态码分布饼图,以及响应时间过长的请求比例。
这三类指标,趋势反映外部流量,质量反映生成器状态,异常反映潜在故障,组合起来一眼就能看出系统是否健康。
5.2 Dash实现思路
写Dash看板的流程比较固定:先创建app,再定义layout布局,最后用callback把交互逻辑绑定上去。我当时只用了静态展示和简单的日期筛选:
import dash from dash import html, dcc from dash.dependencies import Input, Output import plotly.express as px import pandas as pd app = dash.Dash(__name__) # 省略数据读取和清洗步骤 df = pd.read_sql("SELECT * FROM access_log", conn) app.layout = html.Div([ dcc.Graph(id="trend-chart"), dcc.Interval(id="interval", interval=60000, n_intervals=0) ]) @app.callback( Output("trend-chart", "figure"), Input("interval", "n_intervals") ) def update_trend(n): # 重新读最新一小时的聚合结果 latest = fetch_hourly_trend() return px.line(latest, x="hour", y="request_count")这个版本虽然简陋,但已经足够支撑日常的巡检。加上dcc.Interval定时刷新之后,看板挂在办公室大屏上,每天扫一眼就能了解工具运行情况。
5.3 用“纯生成方案”得到的结论
看板搭完,我盯着那几条曲线看了几分钟,有几个直观感受值得记录下来。
下午2点到4点这个时段,请求量确实有明显波峰,但高峰时段生成成功率和平均响应时间居然没有明显变差,说明当前的服务能力还够用。倒是有意思的是,每天凌晨那批定时任务会在非高峰时段触发,导致凌晨2点附近出现一个小高峰,一开始没意识到是这个原因,查了半个多小时。
质检这块,校验通过率稳定在94%左右,余下6%里有一大半是原文太短、摘要内容本身就不充分导致的,真正被模型“创造性发挥”带偏的比例不高。这意味着短期不需要大改生成逻辑,而是应该继续积累边界样例,把校验规则做得更细。
这些结论全部来自看板数据的直接观察。做数据可视化,除了把指标摆上去,更重要的一步是对照业务逻辑去解释曲线,否则看板就只是个好看的花架子。
6. 学习笔记的方法论:记录结构比记录字数重要
最后想聊点跟技术无关、但对学习效率影响很大的东西。
6.1 今天的笔记是怎么组织的
回看我这一天记下来的东西,真正让我觉得有价值的不只是把功能跑通了,而是每个环节都留下了“为什么会这么做”的记录。比如提示词为什么要分优先级、日志为什么加安全字段、看板为什么不堆指标,这些问题如果当时不记,三天之后再看代码就需要重新推演一遍。
所以我的笔记结构一般分三段:做了什么、为什么这么做、踩了什么坑。今天这篇的每一节其实都对应了这三问。
6.2 中间产物千万别丢
做摘要生成的时候,第一版提示词和第一批输出结果我全都存了下来。当时只是随手保存,后面调试的时候这些中间产物成了最宝贵的对照样本——能清楚地看到参数改动导致输出发生了什么变化。
如果你的项目也有类似情况,强烈建议给中间产物单独建一个目录,按日期+环节命名。别怕麻烦,这个习惯能省下大把重复排查的时间。
6.3 下一步的扩展思路
这套链路跑通之后,后续可以扩展的方向也清楚了。校验规则可以引入更多维度,比如摘要里是否包含原文没有的时间或人名这类幻觉实体;日志采集侧可以接更完整的消费管道,把数据从本地文件迁到分析型数据库;看板则可以把生成器的成本指标一起纳入,算一算每条有效摘要的综合开销。
学习笔记的价值并不在于记了多少,而在于前后能不能连起来。今天这一天,我从一个写不好提示词的摘要工具开始,一路做到日志清洗、看板监控,整个链路自然闭环了。比起单独记住某个函数的用法,这种“用起来”的理解方式扎实得多。