
1. 这个工具到底在解决什么问题先说说我做这个项目的起因。去年夏天有个朋友吃完凉拌芹菜去海边玩回来胳膊上起了一片红疹又痒又痛去医院才知道是植物性日光性皮炎。医生问她吃了什么她想了半天才想起来中午吃了一大碗芹菜。这件事让我意识到一个问题光敏食物这个概念绝大多数人根本没听过更别说知道自己刚吃下去的东西会不会让自己变成“见光死”。所谓光敏食物就是含有呋喃香豆素类化合物的一类食材。这类物质本身无害但进入人体后如果遇到紫外线照射会引发光毒性反应轻则皮肤红肿瘙痒重则起水泡、色素沉着甚至需要就医。常见的包括芹菜、香菜、柠檬、无花果、灰菜、苋菜等覆盖蔬菜、水果、香料多个类别日常饮食中撞上的概率远比想象中高。但问题在于现有的信息获取方式太割裂了。你要么去搜一篇科普文章看完记住几个名字过两天全忘了要么去查医学文献专业术语一大堆普通人根本读不下去。更关键的是每个人的情况不一样——你吃了多少、什么时候吃、要去做什么、你的皮肤类型如何这些变量组合起来风险等级完全不同。一个静态的“光敏食物列表”解决不了动态决策的问题。所以我做了这个光敏食物检测与动态决策科普工具。它的核心思路是用LLM做底层推理引擎结合一个结构化的光敏食物知识库根据用户输入的食材、摄入量、时间、活动场景、肤质等信息实时输出个性化的风险评级和行动建议。同时它还是一个科普工具会在给出结论的同时解释背后的原理让用户不仅知道“能不能吃”还知道“为什么”。这个项目适合几类人参考一是想入门LLM应用开发的开发者这是一个完整的RAG加决策推理的实战案例二是对健康科普工具有兴趣的产品同学可以看到如何把专业知识转化成普通人能用的交互三是单纯想了解光敏食物知识的普通读者直接看里面的知识库内容和决策逻辑也能有收获。2. 整体设计思路与关键技术选型2.1 为什么选LLM而不是规则引擎最开始我尝试过纯规则引擎的方案。逻辑很简单建一张光敏食物表每种食物标注风险等级用户选了食材就查表输出结果。但很快发现这条路走不通。第一个问题是组合爆炸。光敏反应的风险不是简单叠加的。你吃了芹菜又吃了柠檬风险不是1加1等于2而是可能因为呋喃香豆素种类不同产生协同效应。再加上摄入量、时间间隔、紫外线强度、个人肤质这些维度规则表会膨胀到无法维护。第二个问题是解释性。规则引擎只能输出“高风险”三个字但用户需要知道为什么。是因为芹菜里的补骨脂素含量高还是因为吃完不到两小时就暴露在强紫外线下这些解释需要自然语言生成能力规则引擎做不来。第三个问题是长尾覆盖。光敏食物不止那十几种常见的很多冷门食材也有光敏潜力。规则表不可能穷举但LLM可以基于化学结构知识进行推理对没见过的食材也能给出合理判断。所以最终方案是LLM作为推理和生成引擎结构化知识库作为事实锚点两者结合。知识库保证核心事实准确LLM负责灵活推理和自然语言解释。2.2 RAG架构的具体落地方式这里用的是经典的RAG模式但做了一些针对性的调整。整体流程分四步第一步知识库构建。我把光敏食物相关的信息整理成结构化文档每条记录包含食物名称、别名、主要光敏成分、成分含量范围、常见摄入量、风险等级基线、相关文献来源。这些文档被切分成适合检索的片段存入向量数据库。第二步用户输入解析。用户输入的是自然语言比如“我中午吃了一大盘凉拌芹菜下午两点要去海边”。LLM首先做意图识别和实体抽取把食材、摄入量、时间、活动场景这些关键信息结构化出来。第三步知识检索与推理。根据抽取的实体从知识库中检索相关食物信息然后LLM结合检索结果和用户的具体场景进行推理。这一步不是简单的查表而是要考虑时间间隔、摄入量修正、活动强度等多个因素的交互。第四步结果生成与科普解释。输出包含三部分风险等级、行动建议、原理科普。风险等级用颜色和文字双重标识行动建议具体到“建议推迟到几点出门”“需要涂多高倍数的防晒”科普部分用通俗语言解释光敏反应的机制。2.3 知识库的结构设计知识库是整个工具的事实基础设计上我分了三个层次基础层是食物条目每种食物一条记录包含名称、别名、光敏成分、含量数据、风险基线。这部分数据主要来自公开的食品化学文献和皮肤科临床资料。规则层是决策逻辑定义了各种修正因子。比如时间因子摄入后1到4小时是风险高峰期超过8小时风险显著下降。摄入量因子以常见份量为基准翻倍则风险等级上调一级。肤质因子白皙皮肤对紫外线更敏感风险等级需要上调。解释层是科普内容每个风险等级对应一套通俗解释模板LLM会根据具体场景填充细节。比如同样是高风险吃芹菜去海边和吃无花果去爬山解释的侧重点会不同。这种分层设计的好处是知识库更新时只需要改对应层不会牵一发动全身。新增一种食物只需要加一条基础层记录决策逻辑和解释模板可以复用。3. 核心细节解析与实操要点3.1 光敏食物的风险分级逻辑风险分级不是拍脑袋定的背后有一套计算逻辑。我参考了皮肤光毒反应的相关研究把风险拆解成三个维度成分维度看的是食物中呋喃香豆素的种类和含量。补骨脂素和异补骨脂素的光毒性最强欧前胡素次之花椒毒素再次。含量方面以每100克食材中的总呋喃香豆素毫克数计超过50毫克算高含量10到50毫克算中等低于10毫克算低。摄入维度看的是实际吃进去的量。这里有个容易被忽略的点烹饪方式会影响光敏成分的保留率。凉拌芹菜的光敏成分保留率接近100%但焯水后可能降到60%到70%长时间高温炖煮可能降到30%以下。所以同样是吃芹菜凉拌和炖汤的风险完全不同。暴露维度看的是紫外线照射条件。这里要考虑季节、时段、纬度、海拔、天气。夏天中午的紫外线强度是冬天傍晚的十几倍高原地区比平原地区强百分之三十以上。用户不需要输入这些具体参数但LLM会根据用户描述的场景做合理推断。三个维度综合起来最终输出五个风险等级极低、低、中、高、极高。每个等级对应不同的行动建议。3.2 时间窗口的计算与修正时间因素是光敏反应里最关键的变量之一。呋喃香豆素进入人体后需要经过消化吸收才能分布到皮肤。这个过程通常需要30到60分钟然后血药浓度在1到2小时达到峰值之后逐渐代谢。所以风险的时间曲线是这样的摄入后0到30分钟风险较低因为成分还没吸收30分钟到1小时风险快速上升1到4小时风险处于高峰期4到8小时风险逐渐下降超过8小时风险显著降低但并非为零因为部分成分可能储存在脂肪组织中缓慢释放。这个曲线意味着如果用户说“我刚刚吃了一盘芹菜马上要出门”和“我三小时前吃了芹菜现在要出门”风险等级是完全不同的。前者处于上升期后者处于高峰期后者反而更危险。实操中还有一个细节个体代谢差异。有些人代谢快高峰期可能只有2小时有些人代谢慢可能持续6小时。这个信息用户通常不知道所以我在工具里默认用平均值但在科普部分会提示“如果你知道自己代谢较慢建议把时间窗口往后延”。3.3 肤质与用药情况的修正因子肤质对光敏反应的影响很大。Fitzpatrick皮肤分型是皮肤科常用的分类方法I型最白VI型最深。I型和II型皮肤对紫外线极其敏感同样的光敏物质摄入量他们出现反应的概率是IV型皮肤的3到5倍。工具里让用户选择自己的肤质类型如果不确定可以用一个简单的自测你夏天第一次晒太阳多久会晒红。15分钟以内是I型15到30分钟是II型30到60分钟是III型超过1小时是IV型及以上。这个自测虽然不是精确诊断但足够用于风险分级。另一个重要的修正因子是用药情况。很多药物本身就有光敏性比如某些抗生素、利尿剂、降糖药、抗抑郁药。如果用户正在服用这些药物即使食物本身风险不高叠加起来也可能达到高风险。工具里会询问用户是否在服用已知的光敏药物如果是风险等级自动上调一级。注意工具不能替代医生诊断。如果用户已经出现了光敏反应症状比如皮肤红肿、瘙痒、水泡工具会直接建议就医不再输出风险分级。3.4 LLM提示词的设计要点提示词是整个工具的大脑设计好坏直接决定输出质量。我前后改了十几版总结出几个关键点第一角色设定要具体。不能只说“你是一个助手”而是要说“你是一个皮肤光毒反应领域的科普专家擅长用通俗语言解释复杂的生化机制同时具备严谨的风险评估能力”。角色越具体LLM的输出越稳定。第二输出格式要约束。我要求LLM必须按照固定结构输出风险等级、核心原因、行动建议、科普解释。每个部分有字数限制风险等级只能是五个枚举值之一行动建议必须包含具体的时间或数值。这样避免了LLM自由发挥导致的格式混乱。第三推理过程要显式。我让LLM在给出最终结论前先列出它的推理步骤识别到的食材是什么、检索到的光敏成分是什么、时间窗口处于哪个阶段、修正因子有哪些、最终风险等级如何得出。这个推理链不仅让输出更可靠也方便调试时定位问题。第四安全边界要明确。提示词里明确写了不提供医疗诊断不推荐具体药物不替代专业医疗建议。如果用户描述的症状超出科普范围直接建议就医。3.5 知识库的更新与维护知识库不是建完就完了需要持续维护。我设了一个简单的更新流程每月检查一次新发表的食品化学和皮肤科文献看有没有新的光敏食物被发现或者已有食物的光敏成分数据被修正。每季度根据用户反馈调整风险分级比如某种食物的实际风险比预期高或低就修正它的基线等级。每年做一次全面审核确保所有数据来源可靠、引用规范。更新时要注意版本管理。每次修改知识库都要记录改了什么、为什么改、影响哪些食物。这样如果发现某个修改导致输出异常可以快速回滚。4. 实操过程与核心环节实现4.1 知识库的构建流程知识库构建分四步走第一步数据收集。我从三个来源收集数据公开的食品化学数据库、皮肤科教科书和临床指南、已发表的光敏反应病例报告。每个来源的数据都标注出处方便后续核查。第二步数据清洗。收集来的数据格式五花八门需要统一。我定义了一个标准模板每条食物记录包含中文名、英文名、别名、主要光敏成分、含量范围、常见份量、风险基线、数据来源。清洗时特别注意单位统一含量统一用毫克每100克份量统一用克。第三步向量化入库。每条记录被转换成一个文本片段然后用嵌入模型转成向量存入向量数据库。检索时用余弦相似度找最相关的条目。这里有个细节别名也要入库。比如“芫荽”和“香菜”是同一种东西如果只存一个名字用户输入另一个就检索不到。第四步测试验证。构建完成后我用一批测试用例验证检索准确性。比如输入“芹菜”应该能检索到芹菜条目输入“欧芹”应该能检索到欧芹条目并提示它和芹菜是不同物种但都含光敏成分。4.2 用户输入解析的实现用户输入解析是LLM的第一个任务。我用的提示词大致是这样的你是一个信息抽取助手。请从用户的描述中提取以下信息 1. 食材名称可能多个 2. 摄入量用常见份量描述如“一盘”“一碗”“一个” 3. 摄入时间距离现在多久 4. 计划活动如“去海边”“爬山”“日常通勤” 5. 肤质类型如果用户提到 6. 用药情况如果用户提到 如果某项信息用户没有提供标记为“未提供”。 输出格式为JSON。这个步骤的关键是容错。用户可能说“我吃了点芹菜”摄入量不明确也可能说“下午要出门”时间不明确。LLM需要能处理这些模糊输入标记为未提供然后在后续推理中用默认值或追问。实测下来LLM在实体抽取上的准确率很高但偶尔会把“芹菜”和“香菜”搞混因为两者在中文里经常一起出现。解决办法是在提示词里加一句“注意区分芹菜和香菜它们是不同的食材”。4.3 风险推理的核心逻辑风险推理是整个工具最核心的部分。LLM拿到结构化的用户信息和检索到的知识库内容后按照以下逻辑进行推理第一步确定基础风险。根据食材从知识库中查到风险基线。如果用户吃了多种食材取最高风险等级作为基础然后根据食材数量做微调。两种中等风险食材叠加可能升到高风险三种以上直接按高风险处理。第二步应用时间修正。根据摄入时间判断处于风险曲线的哪个阶段。高峰期不修正上升期降一级下降期降一级超过8小时降两级。第三步应用摄入量修正。以常见份量为基准用户摄入量明显偏大则升一级明显偏小则降一级。第四步应用肤质和用药修正。I型或II型皮肤升一级正在服用光敏药物升一级。第五步应用活动场景修正。高强度户外活动升一级日常通勤不修正室内活动降一级。第六步综合输出。所有修正叠加后映射到最终的五级风险。如果修正后超过极高仍然按极高处理但会在建议中强调“强烈建议避免外出”。这个逻辑链看起来复杂但LLM处理起来很快整个推理过程在几秒内完成。关键是提示词要把每一步都说清楚让LLM按步骤走不要跳步。4.4 输出生成与科普解释输出生成是用户直接看到的部分我设计了固定的四段式结构第一段是风险等级用大字和颜色标识。极低是绿色低是浅绿中是黄色高是橙色极高是红色。文字部分写“当前风险等级高”。第二段是核心原因用一两句话概括为什么是这个等级。比如“你摄入的芹菜含有较高浓度的补骨脂素摄入后2小时处于光敏反应高峰期且计划前往海边属于高强度紫外线暴露场景”。第三段是行动建议要具体可执行。比如“建议将外出时间推迟到摄入后6小时以上”“外出时穿长袖长裤暴露部位涂抹SPF50以上的广谱防晒霜”“避免在上午10点到下午4点之间进行户外活动”。第四段是科普解释用通俗语言解释光敏反应的机制。比如“芹菜中的补骨脂素是一种光敏物质它进入皮肤后遇到紫外线会吸收光能并释放活性氧这些活性氧会损伤皮肤细胞导致红肿、瘙痒甚至水泡。这个过程需要一定的时间积累所以刚吃完时风险不高1到4小时后达到峰值”。科普部分的语言要特别打磨。我试过直接让LLM解释“呋喃香豆素的光毒性机制”输出全是专业术语普通人看不懂。后来改成“你可以把补骨脂素想象成一个被紫外线激活的小炸弹它平时安静地待在皮肤里一旦被阳光照到就会爆炸炸伤周围的皮肤细胞”用户反馈好多了。4.5 交互界面的设计考量界面设计上我遵循一个原则不要让用户做选择题让用户讲故事。传统的健康工具喜欢用下拉菜单和复选框用户要在一堆选项里找自己的情况。但这个工具的目标用户是普通人他们不知道“Fitzpatrick分型”是什么也不知道“呋喃香豆素”怎么拼。所以界面就是一个大的输入框用户用自然语言描述自己的情况。比如“我中午吃了一盘凉拌芹菜下午两点要去海边游泳我皮肤比较白”。工具解析这段话提取所有需要的信息然后输出结果。如果信息不够工具会追问。比如用户只说“我吃了芹菜”工具会问“大概吃了多少什么时候吃的接下来有什么户外活动计划”追问不超过两轮避免用户失去耐心。界面上还有一个“了解更多”的折叠区域点开可以看到光敏食物的完整列表和详细科普。这个设计是为了满足不同深度的需求只想快速决策的用户看完风险等级就走想深入学习的用户可以展开阅读。5. 常见问题与排查技巧实录5.1 检索不准怎么办问题表现用户输入某种食物检索到的条目不对或者检索不到。排查思路首先检查知识库里有没有这个食物。如果没有需要补充。如果有但检索不到检查别名是否完整。比如“圣女果”和“小番茄”是同一种东西如果只存了一个名字另一个就检索不到。解决方法在知识库构建时每种食物尽量收录所有常见别名。另外检索时可以用模糊匹配比如用户输入“芹菜”除了精确匹配“芹菜”还可以匹配包含“芹菜”的所有条目比如“芹菜”“西芹”“水芹”。预防措施定期用一批测试用例跑检索看有没有遗漏。测试用例要覆盖常见食物、冷门食物、别名、错别字。5.2 LLM输出格式不稳定问题表现有时候LLM不按要求的格式输出比如漏掉某个部分或者风险等级用了非枚举值。排查思路检查提示词是否足够明确。如果提示词只说“输出风险等级”LLM可能输出“较高”“中等偏上”这种非标准值。如果提示词说“风险等级只能是极低、低、中、高、极高之一”输出就稳定多了。解决方法在提示词里用枚举值约束输出并且在输出后加一个校验步骤。如果LLM输出的风险等级不在枚举值里自动映射到最接近的值。预防措施每次修改提示词后用一批测试用例跑一遍看输出是否稳定。测试用例要覆盖各种边界情况比如信息不全、食材冷门、场景复杂。5.3 风险等级偏高或偏低问题表现用户反馈某种食物的风险等级和实际体验不符。比如工具说高风险但用户吃了之后没事或者工具说低风险但用户吃了之后出现了反应。排查思路首先检查知识库里的风险基线是否准确。如果基线偏高或偏低修正基线。如果基线没问题检查修正因子是否合理。比如时间修正是否过于激进肤质修正是否过于保守。解决方法根据用户反馈调整修正因子的权重。调整时要小步走每次只改一个因子观察效果。改完后用历史数据回测看整体准确率是否提升。预防措施建立用户反馈机制让用户可以报告“结果不准”。收集足够多的反馈后做统计分析找出系统性偏差。5.4 用户输入信息严重不足问题表现用户只说“我吃了芹菜”没有时间、份量、活动场景信息。排查思路这种情况下不能强行推理否则输出会很不准确。需要追问但追问要有技巧不能像查户口一样问一堆问题。解决方法设计追问策略优先问最关键的信息。时间是最关键的因为时间窗口对风险影响最大。其次是活动场景因为决定了紫外线暴露强度。份量和肤质可以放在最后如果用户不提供就用默认值。预防措施在界面设计上引导用户提供完整信息。比如输入框的占位符写“例如我中午吃了一盘凉拌芹菜下午两点要去海边”给用户一个参考模板。5.5 常见问题速查表问题类型典型表现排查方向解决手段检索不到输入食物无结果知识库是否收录补充条目和别名格式混乱输出缺段或枚举值错误提示词约束是否明确加枚举约束和输出校验等级偏差风险与实际体验不符基线或修正因子是否合理调整权重并回测信息不足用户输入过于简略追问策略是否有效优化追问优先级响应太慢等待时间超过5秒检索或推理是否耗时优化检索策略或缓存结果实操心得知识库的别名收录是最容易被忽略但最影响体验的环节。我一开始只收了学名结果用户输入“香菜”检索不到“芫荽”输入“圣女果”检索不到“樱桃番茄”。后来花了一个下午专门补别名检索准确率从70%提升到95%以上。6. 后续可以扩展的方向这个工具目前是一个最小可用版本但扩展空间很大。我自己在用的过程中觉得有几个方向值得继续做。第一个方向是图像识别。现在用户需要手动输入食材名称但如果能拍照识别体验会好很多。用户拍一张餐桌照片工具自动识别里面的光敏食物然后结合其他信息给出风险评级。这个需要接入视觉模型技术上可行但需要解决食物识别的准确率问题。第二个方向是地理位置和天气集成。现在的活动场景是用户手动描述的但如果能获取用户的地理位置和当天的紫外线指数风险评级会更精确。比如同样是“去海边”三亚和青岛的紫外线强度差很多风险等级也应该不同。第三个方向是个性化学习。每个用户的代谢速度、皮肤敏感度都不同如果工具能记录用户的反馈逐渐学习用户的个体特征风险评级会越来越准。比如用户反馈“上次说高风险但我没事”工具可以适当调低该用户的风险敏感度。第四个方向是食物组合分析。现在工具处理多种食材时是取最高风险加微调但实际上不同光敏成分之间可能有协同或拮抗效应。如果能建立更精细的组合模型多食材场景的评级会更准确。第五个方向是科普内容的多模态化。现在的科普是纯文字如果能加入示意图、动画、短视频用户理解起来会更容易。比如用动画展示补骨脂素被紫外线激活的过程比文字描述直观得多。这些方向不需要一次性全做可以按优先级逐步迭代。我的建议是先做图像识别和地理位置集成因为这两个对用户体验提升最明显技术难度也相对可控。最后分享一个我在开发过程中踩过的坑不要试图让LLM做所有事。一开始我想让LLM直接从零推理风险等级不给它知识库结果输出很不稳定同样的输入有时候说高风险有时候说低风险。后来改成LLM只负责推理和生成事实判断交给知识库输出就稳定多了。LLM很强但它不是数据库该查表的时候还是要查表。