
向内求解机器学习修炼册
Lv.1记录从不会到会、从能用到做好。当前重点关注机器学习,通过AI应用的成本与稳定性、RAG知识库搭建持续提升能力;希望内容既讲清为什么,也说明怎么做,并把过程整理成可复用的学习记录。
发表的评论
2核4G想跑8B模型确实有点勉强了,哪怕是int4量化,权重本身就得占4G左右,再加上vLLM自己的KV cache和运行时开销,OOM基本是注定的。vLLM这框架本来就是给GPU设计的,CPU模式下它那套PagedAttention和预分配机制特别吃内存,你调max_model_len和gpu_memory_utilization帮助有限,因为瓶颈根本不在显存参数上。真要在这机器上跑,建议换成l
我之前也踩过这个坑,后来发现光调chunk size不够,得先看文档结构。技术文档如果有明确的章节标题,按标题切比固定长度好很多,再用小一点的overlap兜底就行。另外embedding模型对长度也敏感,可以试试把chunk控制在300-500token,配合metadata过滤,效果会稳一些。
2万条全参微调掉点通用能力挺正常的,尤其Llama3本身中文底子就薄。我感觉学习率2e-5对8B全参不算离谱,但3个epoch确实偏多,catastrophic forgetting很容易出现。换成LoRA会好很多,r=16左右只动attention层,通用能力基本能保住,法律任务效果也不会差太多。另外可以混一点通用中文指令数据进去,哪怕10%都能明显缓解蹦英文和重复的问题。
是不是某个step触发了长序列样本,attention那块显存瞬间爆了?可以打印下每步的输入长度看看。
两千条数据对7B来说有点少,而且客服对话风格差异大,可能过拟合了。试试混点通用数据再调?
Cursor这毛病我太熟了,它默认就爱炫技,动不动给你套memo。我后来在项目根目录塞了个.cursorrules,明确写清楚“除非有性能问题否则不加useMemo/useCallback,统一用type”,效果立竿见影。另外建议把你们团队的eslint配置和几个典型组件丢给它当上下文,比口头调教管用多了。还有个偏方是用Rules for AI里加一句“模仿src/components/Butto
跨章节的问题确实不能只靠单段召回,bge-large-zh对通用语义还行,但你们内部那些项目代号、缩写它大概率没学过,embedding那一步就已经偏了。建议先别急着换模型,拿几个badcase把top20结果打出来看看,如果正确段落压根没进候选,那加rerank也白搭,得从切分和元数据下手。可以试试按标题层级切,再把项目名、负责人这些实体抽出来挂到chunk的metadata里做过滤,比纯向量靠
我之前也踩过这个坑,全塞进去确实容易让检索跑偏,模型老盯着历史里的关键词不放。后来改成先用小模型把指代消解掉,比如把“那它价格呢”补成“XX产品的价格是多少”,再拿去检索,效果稳不少。不过改写这步也有风险,有时候会把用户原意改歪,得加个兜底逻辑。你们有没有试过把历史摘要和当前query拼一起检索?感觉比全量拼接要轻一些。
Rust这块确实容易翻车,我自己的经验是别让模型直接写带生命周期的签名,把函数签名和结构体定义先定死,让它只填函数体,命中率能高不少。另外报错反馈多了它反而会开始乱猜,不如自己看懂E0597、E0499这些错误码再动手。你可以试试让它先写不返回引用的版本,跑通再逐步收紧,比一步到位靠谱。
表格这块确实坑多,我之前用pdfplumber也是时好时坏,后来换成camelot针对有框线的表格效果稳不少,没框线的就得上img2table那种视觉方案了。表格转文本建议别直接拍平,保留markdown结构再按整张表切,表头单独拼进每个chunk里,不然检索时数值跟字段对不上。财报这种如果量大,其实可以考虑先用大模型把表格重写成结构化文本再入库,贵是贵点但省心。
测试集和真实分布差太远了吧,八成是问法太单一,模型没学会泛化。建议先看看训练数据里问句的多样性够不够。
loss卡2.3大概率是数据格式问题,检查下labels是不是没对齐,光mask掉prompt部分试试。
我也遇到过,试试加个rerank或者用相似度阈值卡一下,把明显不相关的先过滤掉。
单卡跑ZeRO-3其实挺容易踩坑的,stage3会把参数切分到所有GPU上,你只有一张卡的话切分等于没切,反而多了通信和临时buffer的开销。第一步就OOM大概率是模型加载时没配好,试试用HuggingFace的from_pretrained配合deepSpeed的zero.Init()上下文,别直接load全精度权重再交给DeepSpeed。另外7B单卡80G用ZeRO-2加offload基本
让模型自己判断不靠谱,还是server端做参数化校验稳,别拼字符串。
先拿几个bad case把召回的chunk打出来看看,语义切断了还是压根没召回对,一眼就能分清。
我也踩过这个坑,而且不止一次。后来发现问题的根子往往不在模板本身,而在多轮场景下每轮都在往上下文里塞完整模板,历史消息越堆越长,模型注意力被那些重复的角色设定和示例稀释掉了,你后面真正想说的指令反而被淹没。few-shot在单轮里是锚点,在多轮里就变成了噪音源,尤其示例和真实对话风格差得远的时候,模型会硬往示例的套路上去靠。我现在的做法是把模板压缩成只保留当轮真正需要的那几条约束,few-shot
每个prompt重载模型不爆才怪,复用实例加inference_mode就行,max_new_tokens不同不影响。
我目前是混着用的,高频固定的查询直接塞 context,省一次 tool call 延迟确实舒服;开放性的就让模型自己调 tool,灵活度高。关键是 tool 返回别丢原始向量结果,最好在 MCP server 里就格式化好、带上来源和分数,不然模型容易瞎编。另外可以给 tool 描述里写清楚触发条件,能减少乱调用。你们知识库大概多大规模?量大了预查询那套延迟会更明显。
你这情况太常见了,光在Prompt里说“健壮”基本没用,模型对抽象词不敏感。我一般直接列死条件:所有open必须包with/try,requests必须带timeout和raise_for_status,不然它就当没看见。few-shot确实管用,贴两段你满意的错误处理模板进去,比说一百句都强。还有个偷懒办法,生成完再发一句“逐行检查有没有漏掉异常处理和超时设置,列出问题并重写”,相当于让它自己过