先交代一下背景。家父痛风十几年尿酸最高冲到过620μmol/L每次发作都是半夜脚趾头火辣辣地疼饭桌上这不敢吃那不敢碰朋友圈里转来的“痛风食物大全”又互相打架。我一开始只想做一个方便全家查询的痛风饮食清单结果做着做着就变成了标题里那个“吃不停的Agent”把痛风指南、嘌呤表、药物说明书、病友经验全部吞进知识库再通过对话机器人的方式回答“今天能吃什么、不能吃什么、该不该去问医生”。这里面的“吃不停”有两层意思。第一层是痛风本身就是靠饮食管理驱动的慢病食物嘌呤、酒精、果糖、汤底这些东西都得逐条查、反复核占用的不是记忆而是“查询能力”第二层是Agent的运转方式——它不像传统知识库那样“导一次就完事”而是持续从PDF、公众号文章、Excel表、网页里抓内容清洗、切片、向量化入库像不停地吃东西一样把知识消化掉。我实际用到的组合是Obsidian做笔记底座Dify做RAG知识库和Agent编排BGE系列做嵌入与重排再配一个定时脚本每天把新内容丢进流水线。这套搭法对做个人知识库和Agent开发的人都有参考价值尤其适合健康、饮食、法规这类“内容持续变化”的垂直领域。1. 项目到底在做什么把痛风资料变成“会吃”的智能体1.1 痛风知识库解决什么痛风的资料散得离谱。医院给的小册子是PDF营养科发的是Word转来的图片网上文章说的是“中等嘌呤”表格又只给每100g含多少mg单位还不统一。真要回答“我今天吃了半斤酱牛肉、喝了一碗火锅汤尿酸520要不要加药”靠人脑翻资料基本不可能。知识库的价值就是把散乱的资料变成结构化数据食物有嘌呤等级药物有相互作用指南有适用条件和更新日期患者有历史尿酸值全部放在同一个地方让Agent查得到、算得清、答得稳。说白了这套系统的第一使命不是“生成”而是“检索核对”。痛风患者问出来的问题往往非常具体能不能吃豆制品动物内脏到底多危险啤酒和白酒哪个更伤这些问题如果没有权威数据支撑模型很容易一本正经地胡说八道。所以我把大约500篇经过筛选的文档、表格和临床指南导入知识库构建了一个个人级别的垂直RAG系统回答时必须引用知识库来源查不到就明确说查不到。系统跑起来后我父亲问得最多的“今天能不能喝点啤酒”“海带是不是高嘌呤”“尿酸降到400是不是可以停药”都开始有了稳定的参考答案哪怕答案需要补充“这个要按医生建议来”也比之前靠记性、靠猜要好得多。1.2 “吃不停”到底是谁“吃不停的Agent”指的是一个自动摄取数据的智能体重点在于它的运行方式定时抓取、增量更新、持续消化。传统知识库是人在喂数据这个Agent是自己找数据。我写了一个Python守护进程每天只做三件事检查订阅的源站有没有更新把新PDF、新表格、新网页抓下来并转成Markdown调用Dify的知识库API做文档分割和向量化入库。如果检测到同一篇文档被修改它会把旧版本标记为过期而不是直接删除方便追源、方便回滚。这部分可能有人觉得多此一举但健康知识更新频率比你想象的高新的痛风管理指南、新药品说明书、新食物成分数据都会让旧答案失效。如果知识库是静态的Agent回答得越自信越危险。让Agent“吃不停”的本意就是让知识库和源站的时效性保持一致。我甚至在脚本里加了一个“更新日志”文件每天早上把昨晚抓到的文档清单发到Telegram全家人能直接看到今天知识库又“吃”了哪些新东西。1.3 这套方案适合谁适合三类人。第一类是想给家人做健康管理工具的人不需要太懂算法照着流程把Markdown文件准备好用Dify的可视化界面就能跑起来。第二类是正在练手RAG和Agent开发的人痛风这个场景比“论文问答”有意思得多因为数据来源杂、单位不统一、答错有代价能逼你把分块、重排、记忆这些细节都做扎实。第三类是做垂直领域知识库产品的人这套“Obsidian RAG 定时摄取Agent”的架构换掉痛风主题就能复用到其它慢病管理、食品营养、企业制度问答上。2. 整体方案选型知识库底座、RAG 与 Agent 怎么拼2.1 知识库底座为什么选 Obsidian我先试过三种底座Notion、开源Wiki系统和Obsidian。Notion的问题是内容多了之后接口慢、离线体验一般而且把全家人的健康数据放在第三方服务上我不放心。开源Wiki系统功能全但太笨重维护成本比内容本身还高。最后选了Obsidian理由很实际它的本体就是本地的Markdown文件夹没有私有格式不存在“平台锁死”的问题双链和标签可以用来表示食物和症状之间的复杂关系配合Git可以把整个向量库的原文版本管理起来哪天Agent抽风改了笔记回滚也很方便。还有一个特别重要的原因Obsidian的Markdown非常适合作为RAG的中间格式。PDF、Excel、网页这些脏数据先被统一洗成Markdown再被切分成块。Markdown天然保留标题、表格、列表结构调用Embedding的时候表格内容不会像纯文本那样被拆得七零八落。如果你整理的是一堆Excel嘌呤表这个优势尤其明显我会在实操章节里展开讲。简单说Obsidian不是被我用成了“笔记软件”而是被我用成了“知识库的工作目录”。2.2 RAG 检索层为什么不能没有向量库一开始我也纠结过是不是直接用大模型的上下文窗口把资料全塞进去就完了。后来一算账就放弃了痛风知识库全量展开大概几十万字主流模型上下文窗口装得下但每次问答都把所有原文发给模型成本高、响应慢还容易把模型注意力稀释掉。RAG的核心是把“全部记住”改成“按需检索”用户问什么就先从知识库里捞出相关段落再把这几段作为上下文交给大模型生成答案。向量库负责把文本变成数字向量并按相似度检索。我用的嵌入模型是BGE-M3中文医疗文本效果好支持长文本对表格文本也能正确处理。向量数据库选了本地的Qdrant也可以直接用Dify内置的向量库个人规模下差别不大。实际操作中我发现纯向量检索对“痛风”和“尿酸高”这种同义改写不够敏感所以在Dify里开了混合检索关键词检索召回精确词向量检索召回语义近义词最后用Rerank模型把两路结果合并排序。这一步是回答质量的分水岭。开源知识库项目现在不少Dify、RAGFlow、MaxKB我都试过Dify对Agent和工作流的整合最省心RAGFlow对复杂PDF的排版解析更强如果你的源文档以扫描件和复杂表格为主可以把RAGFlow作为解析层再喂给Dify做对话。2.3 Agent 框架Dify 还是自研代码Agent在这里不是一个抽象概念而是一套会自己决定调用什么工具、按什么顺序回答问题的程序。我选Dify做Agent编排因为它把知识库检索、模型调用、工具调用、对话记忆都集成在了可视化流程里我不用从零写Agent调度逻辑。但Dify有两种模式Workflow和Agent。Workflow适合流程固定比如“收到提问→查知识库→输出答案”每步都写死Agent适合流程不固定模型根据用户意图自己决定先查嘌呤表还是先查药物信息。很多框架里管Agent调度器的角色叫Agent Harness它的职责就是决定“什么时候调工具、调完怎么办、怎么终止”。理解这个概念就不会把固定流程误当成Agent。痛风问答这个场景我的经验是不要纯Agent也不要纯固定流程而是混合先用Workflow固定好“问题改写→召回→重排→生成答案”的主干再用Agent流处理需要多轮工具调用的复杂提问。比如用户说“我中午吃了腰花、喝了两瓶啤酒现在脚有点疼”模型应该先拆解食物、调嘌呤查询工具、结合尿酸记录、再给出分级建议而不是一上来就背诵知识库段落。这种编排方式在Dify里很轻松就能做出来代码量约等于零真正花时间的是调工具和做评测。2.4 为什么强调“吃不停”而不是一次性导入我把“持续摄取”当成整个项目最重要的设计原则不是故意追求炫技。健康类知识库最大的敌人就是“过期”一份三年前的嘌呤表可能还在把豆制品列为禁食而2023年后的痛风管理指南已经明确豆制品并非绝对禁忌。一次性导入等于给自己埋雷。Agent的任务是每天检查源头更新把新知识“吃”进来用版本号标记旧知识再定期告诉我有多少文档过期了。这个机制让我敢放心说我这个知识库里的答案至少是基于我筛选过的、截止到最近一次更新的资料。3. 落地实操从零建痛风知识库3.1 第一步设计目录结构与元数据目录结构决定了Agent能不能快速找到对应知识块。我用了六个顶层目录诊断与指南、食物嘌呤表、药物与禁忌、症状与发作、生活方式、病友问答。每个目录下再按类型拆分比如食物嘌呤表下面分肉类、海鲜、蔬菜、水果、饮品、调味料。整体的Markdown结构大概是这样的gout-kb/ ├── 01-诊断与指南/ │ ├── 2024痛风诊疗指南.md │ └── 急性期处理.md ├── 02-食物嘌呤表/ │ ├── 肉类.md │ ├── 海鲜.md │ ├── 蔬菜水果.md │ ├── 饮品.md │ └── 调味料.md ├── 03-药物与禁忌/ │ ├── 非布司他.md │ └── 秋水仙碱.md ├── 04-症状与发作/ │ └── 发作日记.md ├── 05-生活方式/ │ ├── 饮水建议.md │ └── 运动建议.md └── 06-病友问答/ └── 常见误区.md每个Markdown文件都带YAML元数据。元数据非常重要它让Agent在回答前可以先做过滤。我常用的字段包括标题、分类、嘌呤等级、单位、适用条件、来源链接、最后更新时间。举个例子一篇关于啤酒的笔记元数据会标明“嘌呤等级中高酒精有诱发风险高”。这样用户问“喝酒到底行不行”时Agent可以先把所有带“酒精”标签的文档筛出来再做向量相似度匹配而不是在几千个块里大海捞针。这里有一个实操技巧不要把“食物名”只写在正文里还要写在标签里。因为很多用户在问“海蛎子”而不是“牡蛎”如果标签带了“牡蛎生蚝别名”召回率会明显提升。我在建库的时候给常见食物统一补过别名后来Agent回答方言称呼类问题基本没翻车。3.2 第二步把 Excel 和 PDF 变成知识库能吃的格式痛风资料里最麻烦的是Excel嘌呤表和扫描版PDF。PDF解析如果是文字版还好扫描版必须先OCR我用PaddleOCR跑了一遍中文表格识别率勉强够用但表格线有时会错位所以OCR之后一定要人工抽查。Excel相对好处理用pandas读取后转成Markdown表格然后再拆成“每行一种食物”的独立文档不要让整张表变成一个巨大的块。这里我踩过一个大坑不同来源的嘌呤值单位不统一有的是mg/100g有的是mg/100ml有的是按“份”算。如果直接入库Agent会把“100g猪肝的嘌呤”和“1份猪肝的嘌呤”混为一谈答案就是错的。我的解决办法是在入库前统一换算成mg/100g并在每篇文档的元数据里写明口径“本数据为食物生重每100g可食部嘌呤含量”。这个字段会在最终回答里原样呈现让使用者自己也知道依据。处理完的表格一般长这样食物嘌呤(mg/100g)等级备注猪肝288高急性期避免鸡胸肉137中限量海带96低可适量啤酒80中高诱发风险高这种表格入库后Agent在回答“猪肝能吃吗”时会直接引用对应行而不是把整张表背一遍。3.3 第三步配置 RAG 入库流水线我在Dify里建了一个“痛风知识库”上传方式分成手动和自动两类。手动方式适合处理医院给的PDF和线下讲座资料直接在界面上传就行。自动方式走API适合每天定时跑脚本检测到新文件后调用Dify的知识库接口完成分段、Embedding和索引更新。分段参数我调过很多次最后的习惯是每块约500字、块与块之间重叠80字按Markdown标题切分优先表格行不跨块。为什么是500字因为痛风饮食问题往往需要同时看“食物嘌呤值”和“食用量建议”块太短只能抓到半个信息块太长又会把不同食物的数据混到同一段里。重叠80字是保险防止一个关键句子被切成两半后两边都不完整。Embedding这一步可以使用Dify默认的OpenAI接口也可以配置Ollama本地模型本地模型会更隐私个人用完全够。整个流水线我放在一台只有16GB内存的旧Mini主机上跑Ollama跑7B模型加Qdrant响应速度大概两三秒足够日常使用。3.4 第四步搭 Agent 对话与工具调用知识库建好只是第一步真正让它好用的是Agent的System Prompt和工具配置。我的System Prompt核心只有三句话第一你是痛风营养助手回答前必须检索知识库第二饮食问题优先查询嘌呤表和诱发因素表药物问题只做科普必须提醒咨询医生第三不知道就承认禁止编造。工具调用方面我给Agent注册了三个工具query_food_purine查食物嘌呤等级和含量、query_medication_interaction查药物与饮食禁忌、record_uric_acid记录并读取历史尿酸值。Dify里可以给每个工具写描述和输入参数SchemaAgent看到用户问“吃XX行不行”时会先提取食物名和食用量再调用工具拿到结构化结果后组织成回答。这里要特别说一下工具返回值也必须结构化。比如query_food_purine返回的应该是一个JSON对象包含食物名、嘌呤值、单位、等级、来源而不是一段自由文本。否则Agent调用完工具后还要自己再从文字里反推字段容易出错。这是我做Agent开发很早就踩过的坑工具输出越规整最终答案越稳。每个人在做自己的Agent时都值得把这个规则写进开发规范里。3.5 第五步接入 Obsidian 和聊天入口Obsidian在这里有两个角色。一个是知识库的编辑界面另一个是Agent的数据源。为了让Obsidian笔记能自动进入Dify我在仓库根目录放了一个scripts/feed_dify.py用watchdog监听Markdown文件变化一旦有新文件或修改就把变更推给Dify API。这个脚本不复杂核心逻辑就是遍历指定目录、找最近修改的文件、判断是否已存在同名文档、调用API上传。建议在脚本里加日志方便排查“改了半天但Agent没更新”的诡异问题。聊天入口我接了两端Web端走Dify自带的对话界面手机上用Telegram Bot。Telegram Bot的做法是写一个简单的webhook服务收到消息就调Dify的chat-messages接口再把回答发回去。你也可以接企业微信或飞书原理一样。对家庭用户来说我建议先不要一上来就追求语音输入、小程序之类花哨的入口先让Agent能在微信或Telegram里稳定回答再用真人的问题反复磨答案质量。4. 关键参数与避坑如何让 Agent 不乱吃、也不漏吃4.1 数据源筛选只信指南不信“博主养生文”给痛风知识库喂数据的标准比普通文档严格得多。我的筛选原则是按重要级排第一步是痛风诊疗指南和临床共识这类文档给出的是诊断标准、尿酸控制目标和治疗建议第二步是三甲医院营养科的膳食指导它们通常有具体的食物嘌呤分级和每日建议第三步是权威学会发布的患者教育材料第四步才是经过交叉验证的病友经验。绝对不要直接抓取自媒体平台的“痛风食物大全”。那些文章互相抄错得离谱比如几年前还流行“所有豆制品都不能吃”后来又反转说“大豆嘌呤是植物性的可以适量吃”。没有权威依据的文档入不了库。我的做法是给每个文档来源打一个可信度标记在RAG检索时可信度低的内容只作为参考不作为唯一依据如果一道题多个文档答案冲突Agent需要在回答里注明“不同资料存在差异更建议参考指南原文”。这套筛选成本很高但它是知识库靠不靠谱的根本。4.2 分块与向量化的关键参数向量化直接决定召回质量关键在于不是“所有文档都用同一个分块参数”。表格型文档和段落型文档要分开处理。表格文档我优先按“一行一种食物”切成短块每块只包含食物名、嘌呤值、等级段落型文档按Markdown标题和500字约束切块确保每个块内部都是一个完整语义单元。用不用长文本模型、要不要Rerank也要根据你的中文语料测试。嵌入模型和检索参数也要一起调。我用的参数组合是Embedding用BGE-M3Rerank用BGE-Rerankertop_k设为6召回后再重排取前3。相似度阈值我试过0.5到0.8最后没有设硬阈值因为医学问题宁可不答也不能漏答如果检索结果确实相关就保留Rerank会负责排序。如果你发现Agent经常答非所问先检查这几个参数大概率是top_k太小或重排模型没生效。调整建议可以记成一张表方便以后再换主题时直接套用参数名推荐值说明chunk_size500太长混主题太短信息不完整chunk_overlap80防止关键句被截断top_k6召回数量要够Rerank挑选rerank取前N3最终上下文保持精炼相似度阈值不设硬阈值靠Rerank排序避免误杀4.3 工具调用给 Agent 装好“筷子”工具调用是Agent能“吃不停”的关键也是失败率最高的地方。我给工具加了三道保险。第一每个工具的描述里都写清楚输入参数的格式比如“食物名必须是中文不要带量词”第二工具返回的JSON里必须带source字段方便Agent在回答里引用来源第三所有工具都有超时和异常返回Agent在工具调用失败时会自动转入兜底话术“这个信息我暂时查不到建议你看医生”。这里有个容易忽略的细节Agent不是一次只调一个工具。用户问“下午吃了海带晚上还要吃火锅有没有事”它可能需要先查海带的嘌呤值再查火锅汤底的嘌呤值最后把两个结果合并成风险结论。所以一定要给Agent设定“最多执行3步工具调用”否则碰到复杂问题它会一遍一遍重试日志里经常出现“agent execution terminated due to error”这类错误。加了这个限制之后整个流程稳定多了Token成本也降了不少。4.4 记忆与更新机制Agent记忆分两块短期记忆和长期记忆。短期记忆就是对话窗口里的上下文Dify会默认保留不用特别处理。长期记忆才是痛风场景的差异化需求用户上一次查的尿酸值、有没有痛风石、对哪些药物过敏这些信息应该跨会话保留。我实现的方式是让Agent调用record_uric_acid工具把关键指标写入SQLite或JSON文件下次提问时自动读取。这样用户不需要每次都重复说自己“尿酸520”Agent能基于历史数值给出更贴合的建议。更新机制上我建议不要只更新正文还要管理“版本过期”。我在每个Markdown文件的元数据里放了updated字段和status字段status可以是active或deprecated。每日脚本抓到新版本文档后会把旧版本标记为deprecated并在检索时排除该块。这样既能保留历史记录又不会让Agent读到过期信息。这个机制值得每个人在做知识库时都加上尤其是食品、医疗这类信息快速变化的领域。5. 实测结果与问题排查5.1 我踩过的四个坑先说说踩坑。第一个坑是分块太粗暴把Excel嘌呤表整表变成一个块结果问“猪肝嘌呤多少”时Agent把整张表都当成上下文回答开头还要硬编一句“根据食物的嘌呤含量表其中”。改成一行一块后回答立刻清爽了。第二个坑是相似度阈值设太高有段时间阈值0.75导致Agent频繁说“知识库中暂无相关信息”误杀了一堆有效的“中等嘌呤”食物降到0.6并加Rerank之后这个现象基本消失。第三个坑是工具返回的自由文本问题前文提过后来所有工具都改成JSON效果立竿见影。第四个坑是忘了给Agent限制工具调用轮数用户连续追问三句食物问题Agent会自己生成假设的工具调用把Token烧掉一大截日志一片报错后来加上最大迭代次数和异常处理稳定多了。5.2 问题排查速查表现象常见原因排查方法Agent答非所问Embedding模型不适合中文医疗内容、分块跨表换BGE-M3表格按行切块经常回答“暂无信息”相似度阈值过高、top_k太小阈值降到0.6top_k调到6工具调用循环报错工具输出非结构化、没有最大轮数工具返回改成JSON限制最多3步Obsidian改了笔记但知识库没更新watchdog脚本路径失效检查目录绝对路径加日志回答说法前后不一致面向文档过少、Rerank未生效加大top_k确认Rerank模型已挂载这张表不是万能药但能覆盖80%的新手翻车现场。如果你用的不是Dify而是自研代码排查思路完全一致先看召回再看重排最后看工具调用日志。日志一定是先知行合一不要凭感觉改参数。5.3 先别急着升级先做评测我曾经犯过一个错误模型换了很多界面做得很漂亮但回答质量没有一套客观标准。后来我建了一个评测集20个问题覆盖食物嘌呤、药物禁忌、痛风急性期处理三类每类问题都给出“期望答案要点”。Agent每改一次代码、调一次参数我就跑一遍这20个问题记录命中率、引用完整度、胡说八道次数。我最初纯向量检索的命中率只有六成多加了结构化元数据和Rerank后稳定在八成五以上。这个评测习惯帮我避免了很多次“感觉变好了但实际变差了”的假象。评测集怎么做很简单选20个真实问过的问题去可靠来源找答案把关键点写成断言然后让Agent回答人工判断是否满足。你甚至可以把它写成JSON文件跑完自动打分。做Agent开发一定要养成这个习惯否则你在优化什么其实自己心里也没底。这也是Agent项目里最容易被忽略的“evals”环节评测集不在多在真。6. 后续可以怎么扩展6.1 从“查食物”到“算风险”现在的Agent还停在“这个食物能不能吃”的程度。下一步我准备加一个风险评分模块输入用户当前尿酸值、是否急性发作、今天吃了什么Agent通过知识库里的诱发因素表和食物嘌呤表算出一个进食风险分数并给出替代食物建议。这不是临床诊断只是把知识库里的多条件规则组合起来但实用性会明显上一个台阶。实现上可以用规则引擎也可以让Agent自己写一段Python计算关键是计算结果要稳定、可解释。6.2 把记忆做成长期健康档案我的最终目标是把Agent的记忆从“近期几轮对话”变成“持续几个月甚至几年的健康档案”。每次问答都记录尿酸值、饮食日记、发作时间然后让Agent定期生成趋势摘要。这个档案也可以导出给医生参考减少门诊时讲不清楚病史的尴尬。实现上用SQLite加一张尿酸记录表就够了难的是怎么让Agent在对话中自然地提问和记录而不是像问卷一样生硬。我现在尝试的方案是Agent只在用户主动提到“今天测尿酸”或“昨天发作了”时才顺手更新档案不主动打扰用户体验会好很多。6.3 一点免责与个人体会这套知识库和Agent是我给家里做的工具核心价值是把散落的健康信息结构化方便我父亲和全家人查询它的上限就是“资料整理助手”不是“在线医生”。所有用药、剂量、急性期处理的内容Agent只会给出科普性说明并提醒咨询专科医生这也是我一直强调让Agent“不知道就承认”的原因。个人做健康类知识库项目一定要把免责边界写进System Prompt否则出了事责任全在开发者身上。最后再分享一个小技巧做完这套系统后我养成了每周扫一遍更新日志的习惯。Agent虽然能自动“吃”但“吃什么”仍然需要人来判断。健康知识库最贵的不是向量化那点算力而是你对每条知识的筛选和维护。这个项目本身不复杂把Obsidian、RAG、Agent三个组件用对了任何人都能在两三天内复刻出属于自己的“吃不停”的知识库Agent。