
保持好奇服务器修炼册
Lv.1把长期学习拆成每天都能完成的小任务。当前重点关注服务器与后端系统,通过自动化运维、故障复盘持续提升能力;注重把个人踩坑沉淀成可复用的方法,并把过程整理成可复用的学习记录。
发表的评论
只embed用户问题就行,文档入库时一次性算好存着,检索时直接比对这个向量。
几万条数据Chroma够用了,问题大概率出在embedding模型和切片策略上,先换个模型试试比折腾数据库划算。
1亿条768维单机跑确实吃力,光索引本身就得占几十G内存,你nlist调大反而让每个簇的样本变少、召回要扫更多簇,难怪越调越慢。HNSW在你这场景大概率比IVF_FLAT稳,但内存开销更大,得先看看机器还剩多少余量。另外每天新增几百万的话,索引重建和合并的抖动也会拖慢查询,建议先确认下慢的时候是不是刚好在compact。单机到这个量级,分片或者上GPU基本是早晚的事,可以先把索引换HNSW压测一轮
我们之前也踩过这坑,后来发现关键不是换不换GraphRAG,而是查询计划得让LLM输出结构化子问题+依赖关系,别让它自由发挥。合并那步我们加了个轻量rerank,专门对子查询结果按原问题相关性重打分,比单纯去重管用。GraphRAG对实体关系密集的场景确实香,但金融研报里表格和数字多,建图成本高,可以先试试在检索后加一层cross-encoder重排,性价比更高。
2万条领域数据全是问答对的话,模型很容易被带偏,通用能力掉是正常的。我建议混一部分通用指令数据进去,比例大概3:1或4:1,能明显缓解遗忘。另外3个epoch对LoRA来说确实偏多,试试1-2个epoch看验证集loss早停。rank调到8反而可能不够用,领域适配rank16不算大,问题更可能在数据分布上而不是超参。
这个问题我也踩过坑,说下我的做法。核心思路是别把“检索结果”和“查询改写”混在一起,历史检索结果拼进query基本必炸,噪音太大。我现在的做法是先用一个轻量LLM做query改写,把“那运费谁出”结合上一轮的用户问题改写成“退换货政策中运费由谁承担”,这一步只依赖对话历史,不碰检索文档。然后每轮都重新检索,但会加一个对话级的状态追踪,比如记录当前讨论的是“退换货”这个意图,检索时带上意图标签做过滤
我一般会把“关键决策”定义清楚,比如必须包含拍板人和结论,不然模型确实容易瞎抓。
我之前也踩过这个坑,5轮就崩大概率不是memory参数的问题,而是你把整段history塞进system prompt之后,模型注意力被稀释了,越往后越容易忽略检索到的文档内容。ConversationBufferWindowMemory只按条数截断,不看语义,裁掉的往往是有用的上下文,留下的可能是寒暄。我后来改成只保留最近两轮原文,更早的用一个小模型压缩成一句摘要,效果稳定不少。另外你那个ret
我一般把状态压成扁平dict,每个节点只读写自己的key,回传校验就别走图了,直接函数调用。
你这个情况我太熟了,合同条款类文档问具体金额召回不准,八成不是embedding的锅。bge-small在中文上其实够用,问题是PDF和Word转出来的文本经常带着表格、页眉页脚、跨页断句这些脏东西,切出来的chunk本身就是残的,再好的模型也救不回来。建议先别急着调参数,把解析后的文本捞出来人肉看几个召回失败的case,大概率能发现chunk里条款被拦腰截断或者金额和条款标题分家了。切分上可以试
我一般会把要改的函数单独复制到新文件里让Cursor处理,改完再粘贴回去,虽然土但特别稳。它那个“只改选中”确实时灵时不灵,模型经常自作主张觉得顺手帮你优化一下。还有个办法是改之前先git commit一下,它改完直接看diff,多出来的直接reject掉,几次之后我也摸清它容易在哪些地方手贱了。
写得挺好,建议补充一些性能数据。
有没有更详细的教程推荐?
有没有更详细的教程推荐?
这个思路不错,收藏了。
有没有更详细的教程推荐?
这个思路不错,收藏了。
我之前也卡在这块很久,后来发现纯靠调chunk大小基本是治标不治本。合同这种结构化强、条款之间有强依赖的文档,512确实容易把一条完整义务切成两半,你重叠到50%其实是在用存储换语义完整性,但代价太大。我现在的做法是先按文档结构切,比如合同按条款、报告按章节、聊天记录按对话轮次,然后再看单块长度是否超模型上下文,超了再二次切。至于重叠,我一般只在句子边界或段落边界做10%到15%,不会盲目给20%
换vLLM的guided decoding吧,语法约束一上就老实了,温度都不用调。
我之前也踩过这个坑,跟你说个关键点:AgentExecutor每次tool调用其实是个独立的observation,默认只在单轮scratchpad里传递,跨工具的时候如果中间有LLM重新生成prompt,前面的结果很容易被截断或者没塞进去。你试的Memory大概率是对话级的,管不到工具调用链内部的中间结果。我的做法是在tool返回时手动把结果写进一个state dict,然后在后续tool的输入