DEMO演示视频demo演示视频项目背景在游戏开发中策划需要维护大量的配置表格——怪物数据、技能参数、Buff效果、新手引导……这些表格通过专用的表格工具编辑导出为.txt文件再经过导表流程转成 Lua最终由 UE 引擎读取作为数据源。一个典型的.txt文件长这样它可能包含多个 Sheet每个 Sheet 有四行元数据表名、字段名、类型、描述后面跟着成百上千行配置数据字段之间用 Tab 分隔还夹杂着是否导表控制列、终身码行、MergeMark 等各种噪声标记。策划每天要在这些表格里填写、修改数据工作量大且容易出错。我希望做一个AI 驱动的数据中心策划只需用自然语言说给新手引导表增加一条跳过教程的引导系统就能自动找到对应的表、生成符合格式的数据、校验通过后写入文件。实现这个目标需要解决三个核心问题让 AI 理解表格结构——.txt文件格式复杂LLM 无法直接理解让 AI 找到正确的表—— 几十张表用户说新手引导时系统得知道该操作哪张让 AI 生成正确的数据—— 类型要对、枚举值要合法、ID 不能重复下面按这三步详细说说每一环是怎么设计的以及为什么这样做。第一步解析 .txt生成 JSON Schema为什么需要 Schema原始的.txt文件对 LLM 来说就是一堆用 Tab 分隔的文本它无法理解第三列是Int类型、第五列的可选值是Safe/Attention/Monster这些信息。而且一张表动辄几千行全部喂给 LLM 既不现实也没必要。我的方案是把 .txt 的结构信息提取成 JSON Schema。Schema 是一种标准化的数据描述格式包含字段名、类型、描述、枚举值等元信息LLM 天然能理解。解析引擎怎么工作txt_parser.py是整个系统的起点。它的工作流程是拆分 Sheet按**********Sheet:XXX标记将一个.txt文件拆分成多个逻辑表解析四行元数据第一行中文表名如新手引导数据表第二行字段名格式为中文名|英文名如引导ID|guide_id第三行类型定义如Int、String、Const(Safe1,Monster2)、List(Int)等第四行字段描述剥离噪声列自动识别并移除是否导表控制列和终身码列过滤噪声行跳过终身码尾行、MergeMark 行等不含实际数据的行类型映射将导表工具的自定义类型Int、Const(...)、List(List(Int))映射为标准 JSON Schema 类型其中类型映射是比较有意思的部分。导表工具支持嵌套类型比如List(List(Int))表示整数二维列表Const(Safe1,Attention2,Monster3)表示枚举。我用正则模式匹配递归处理这些类型转换成对应的 JSON Schema 表示{type:array,items:{type:array,items:{type:integer}}}数据采样蓄水池算法Schema 里除了结构定义还会带几条真实数据样本examples字段。这些样本有两个作用让 LLM 理解数据的风格和数值范围比如伤害值一般在 50-500 之间在后续的向量检索中样本文本也参与语义匹配采样使用的是蓄水池采样算法Reservoir Sampling。这个算法的妙处在于不需要知道总数据量只需遍历一遍数据就能以等概率抽取 K 条样本。对于几千行的表格不需要全部加载到内存流式处理即可。采样时还会自动过滤是否导表0的行这些行虽然存在于文件中但不会被游戏使用确保样本都是有效数据。引用关系扫描ref_scanner.py负责自动发现表与表之间的外键关系。它用两种策略字段名模式匹配识别xxx_id、xxxID这类后缀与已知表名比对描述文本分析从字段描述中提取索引到 xxx_data、引用 xxx 表等关键信息每条引用标注置信度high/medium/low最终生成一个global_refs.json全局引用关系图。这个信息后续在 RAG 检索时会用到——当用户查询某张表时系统能自动附带上下游关联表的信息。最终产出运行python main.py后output/目录下会生成一系列文件output/ ├── rookie_data.schema.json ← 新手引导数据表的 Schema ├── monster_initial_data.schema.json ← 怪物初始数据表的 Schema ├── ... ← 其他表的 Schema └── global_refs.json ← 全局表间引用关系图每个 Schema 文件大约几十行 JSON精确描述了一张表的完整结构是后续所有 AI 功能的基础。第二步构建向量数据库为什么要向量数据库有了 Schema 文件后下一步是让系统能根据用户的自然语言描述找到对应的表。用户可能说新手引导也可能说Buff持续时间还可能说怪物伤害数据——这些描述和表名之间不是简单的字符串匹配关系需要语义理解。向量数据库的原理是把文本转换成高维向量embedding语义相近的文本在向量空间中距离相近。当用户输入查询时也转换成向量然后找出距离最近的几条记录。选型本地模型 ChromaDB考虑到这是公司内部工具我选择了完全本地化的方案Embedding 模型sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2一个支持 50 语言的多语言句向量模型12 层 MiniLM 架构轻量且对中文有不错的效果运行在本地 CPU 上向量数据库ChromaDB轻量级的嵌入式向量数据库数据存储在本地chroma_db/目录无需部署服务选择本地模型而非调用远程 API 做 embedding主要考虑策划的操作频率高每次检索都调远程 API 太慢embedding 质量对中文表名的匹配效果影响很大需要能控制和调优离线环境也要能用两个 Collection 的设计vector_store_builder.py构建了两个独立的 Collectionschema_index表级别的语义文档。每个 Schema 被转化为一段自然语言描述包含表名、中文名、字段列表、字段描述等。用于用户说了什么 → 哪张表最相关的检索。sample_index样本级别的文档。每条样本数据也被索引这样当用户描述具体的数据特征时如持续10秒的Buff能通过样本内容匹配到对应的表。两个 Collection 各司其职后续检索时分别查询、综合打分。文档构造的细节Schema 语义文档不是简单地把 JSON dump 进去而是精心构造的自然语言文本表名: rookie_data 描述: 游戏配置表 [新手引导数据表]rookie_data 中文名: 新手引导数据表 来源文件: 新手引导表.txt 共 15 个字段: - guide_id引导ID类型: Int - guide_name引导名称类型: String - trigger_type触发类型类型: Const(...)可选值: Enter, Click, Auto ...这样做是因为 embedding 模型是在自然语言上训练的给它看的文本越像自然语言生成的向量质量越高。第三步RAG 检索 LLM 生成 写入这是整个系统最核心的一步也是踩坑最多的一步。用户输入一句话系统需要完成检索 → 生成 → 校验 → 写入。3.1 RAG 检索混合策略纯语义检索有一个严重问题中文表名的精确匹配做不好。比如用户输入给新手引导表加一条数据“新手引导这四个字明确指向了rookie_data表。但 embedding 模型可能认为新手引导和新手教程”、引导奖励的语义距离差不多导致rookie_data排名不高。我的解决方案是三路混合检索1中文关键词匹配_keyword_match()方法从用户输入中提取中文关键词与每张表的中文名、来源文件名进行匹配。匹配策略按分数从高到低策略分数示例输入包含完整中文表名0.95“给新手引导表加数据”关键词与表名核心词互含0.90“新手引导” ↔ “新手引导数据表”别名匹配配置文件0.92“新手” → rookie_data别名配置模块关键词匹配0.70“引导” → 引导模块下所有表别名和模块可以在table_aliases.json中自由配置应对策划口语化的表述。2Schema 语义搜索 样本语义搜索同时查询 schema_index 和 sample_index 两个 Collection获取语义层面最相关的表。3分数融合——保底机制三路结果合并后需要一个统一的打分公式。最初的设计是简单加权最终分 关键词分×0.5 Schema语义分×0.35 样本语义分×0.15但实际测试中发现一个严重问题当关键词精确匹配了某张表分数 0.92但这张表恰好没被语义搜索命中Schema 分 0、样本分 0加权后变成了0.92×0.5 0.46反而排在了语义搜索命中的其他表后面这就是所谓的高置信度关键词被低权重稀释的问题。修复方案是加一个保底机制ifkw_score0:weightedkw_score*0.5schema_score*0.35sample_score*0.15final_scoremax(weighted,kw_score)# 关键词分数保底逻辑很简单如果用户输入明确提到了某张表的名字那这张表的最终得分至少不应该低于关键词匹配本身的分数。这个小改动让检索准确率从大约 70% 提升到了 95% 以上。3.2 LLM 数据生成检索到目标表后系统将 Schema字段定义、类型、枚举值、样本数据、用户需求组装成 Prompt发给 Claude API因为工作室有免费的Claude API和gemini APIgemini经常占线所以选用Claude并非不可替换 生成结构化数据。ID 分配代码驱动而非 LLM 决定早期设计中我在 Prompt 里告诉 LLM已有 ID 列表让它自己生成不重复的新 ID。但实际运行中遇到了严重问题一张表可能有上万个已有 IDPrompt 里只能展示前 20 个LLM 生成的 ID 经常和未展示的那些 ID 冲突校验失败后反复重试也解决不了失败率大幅提升还会浪费大量token。最终方案是把 ID 分配从 LLM 手中拿走完全由 Python 代码控制defcompute_next_ids(existing_ids,count):# 找到已有 ID 的最大值从 max1 开始分配startmax(existing_ids)1returnlist(range(start,startcount))Prompt 里直接告诉 LLM“主键 ID 已由系统分配请使用以下 ID[751, 752, 753]”。生成后还会强制回填——不管 LLM 返回了什么 ID都用代码计算的 ID 覆盖fori,rowinenumerate(rows):row[pk_field]assigned_ids[i]这是一个重要的设计原则凡是有确定性答案的事情就不要交给 LLM 去猜。ID 的正确性可以通过简单的代码逻辑 100% 保证没必要依赖 LLM 的概率输出。自然语言解析生成条数用户可能说加3条新数据也可能说增加一条引导。_parse_row_count()用正则从输入中提取数量阿拉伯数字(\d)\s*[条个行]→ “3条” 3中文数字([一二两三四五六七八九十])\s*[条个行]→ “一条” 1默认值如果没有提到数量默认生成 1 条上限保护最多 50 条防止意外3.3 数据校验LLM 生成的数据在写入前必须经过严格校验校验项说明类型检查Int 字段必须是整数Float 必须是数值Bool 必须是 0/1枚举约束Const(Safe1,Monster2)字段只能使用定义内的值必填检查required 字段不能为空主键唯一性ID 不能与已有数据重复数组格式List(Int)字段必须是合法的数组格式校验失败后错误信息会反馈给 LLM 重新生成最多重试 2 次。这个生成-校验-反馈-重试的循环能有效提高数据质量。3.4 安全写入最后一步是把生成的数据写入.txt文件。txt_writer.py负责这项工作几个关键设计定位插入点新数据插入到目标 Sheet 的终身码行之前终身码行是每个 Sheet 的最后一行特殊标记是导表工具管线特有的机制并非通用机制格式化按字段顺序拼接 Tab 分隔行首列补是否导表标记末列自动生成 9 位终身码编码保持检测原文件编码可能是 UTF-8、GBK 等写入时保持一致否则导表工具无法识别原子写入先写到临时文件再 rename 替换原文件防止写入中途崩溃导致文件损坏整体数据流策划的 .txt 文件 ↓ txt_parser.py结构解析 噪声过滤 ↓ data_sampler.py蓄水池采样 ↓ ref_scanner.py引用关系识别 output/*.schema.json global_refs.json ↓ vector_store_builder.py文档构造 Embedding chroma_db/schema_index sample_index ↓ rag_query.py关键词 语义混合检索 保底分融合 ↓ data_generator.pyPrompt 组装 Claude API 代码 ID 分配 ↓ DataValidator类型/枚举/主键校验 ↓ txt_writer.py格式化 终身码 原子写入 写入完成的 .txt 文件实际效果策划输入“给新手引导表增加一条跳过教程的引导”系统执行RAG 检索 →rookie_data92% 关键词匹配自动选择读取已有 750 条数据分配 ID 751调用 Claude 生成一条符合 Schema 的引导数据校验通过类型正确、枚举值合法、ID 唯一写入新手引导表.txt输出变更摘要整个过程约 5 秒策划无需了解表格结构的任何细节。踩过的坑关键词高分被加权稀释上文已述保底机制解决LLM 生成重复 IDPrompt 只展示部分 IDLLM 无法避开全部已有 ID → 改为代码分配embedding 模型对中文表名不敏感纯语义检索对新手引导这类专有名词效果差 → 加入关键词匹配作为补充文件编码不一致写入时不保持原编码会导致导表工具报错 → 写入前检测并保持编码终身码冲突新生成的 9 位终身码可能和已有的冲突 → 生成后全局去重每个坑都对应着代码中的一个具体修复这也是工程和理论的区别——论文里的 RAG 流程图很简洁真正落地时 80% 的工作量都在处理这些边界情况。测试数据重构与RAG验证2026.03为什么重构测试数据之前的测试数据新手引导表、tips弹窗表等过于简单字段少、表间引用稀疏无法充分验证系统在复杂表结构下的表现。于是设计了一套更贴近真实游戏项目的测试数据5个文件、18张表、覆盖角色/技能/Buff/装备/关卡/道具六大系统刻意制造了密集的跨表引用关系。新测试数据设计文件表核心设计意图角色相关表.txthero_base_data, hero_growth_data, hero_talent_data角色基础→成长→天赋的三层引用链技能与Buff表.txtskill_data, skill_effect_data, skill_upgrade_data, buff_data, buff_trigger_data, element_reaction_data技能→效果→Buff的密集交叉引用装备系统表.txtequip_base_data, equip_affix_data, equip_set_data, enhance_cost_data装备→词缀→套装→强化的完整装备链关卡与掉落表.txtstage_config_data, wave_data, drop_group_data, drop_item_data关卡→波次→掉落组→掉落物的四层级联道具总表.txtitem_base_data被多张表引用的基础道具表全链路重建结果Schema生成18张表全部正确解析字段类型、枚举值、描述信息准确引用扫描RefScanner检出41条引用关系33高置信、4中、4低跨文件引用网络与设计完全吻合向量库构建ChromaDB两个集合共107条文档18条表级 89条样本级构建耗时25秒语义搜索准确率测试用12条中文自然语言查询做端到端测试覆盖直接别名、领域术语、模糊描述等场景给角色表加一个新角色 → hero_base_data ✓ (0.920) 增加一个火属性的技能 → skill_data ✓ (0.750) 加一条持续伤害的Buff → buff_data ✓ (0.700) 给装备表增加一把新武器 → equip_base_data ✓ (0.920) 添加一个新关卡 → stage_config_data ✓ (0.920) 增加一条掉落配置 → drop_group_data ✓ (0.920) 加一个新道具 → item_base_data ✓ (0.700) 元素反应水火蒸发 → element_reaction_data ✓ (0.920) 角色天赋 → hero_talent_data ✓ (0.920) 装备套装效果 → equip_set_data ✓ (0.920) 技能升级消耗 → skill_upgrade_data ✓ (0.920) 角色突破升级 → hero_growth_data ✓ (0.773)最终准确率12/12 100%关键发现关键词匹配 语义向量的混合策略非常有效精确别名匹配贡献了0.920的保底高分语义向量负责兜底模糊查询table_aliases.json的模块分组帮助把关卡这类泛化查询正确路由到stage_config_data而非同模块的drop_group_data引用密度影响检索enhance_cost_data和drop_item_data因为被多表引用在多个查询中以第二名出现说明引用关系权重在排序中发挥了作用跨表联动生成2026.03为什么需要跨表联动单表生成能力已经稳定了但真实策划需求往往是跨表的“创建一个新角色亚瑟并为他创造一整套天赋和专属装备设计方案以王者荣耀的亚瑟为模板”这一句话涉及hero_base_data新角色→hero_growth_data成长曲线→hero_talent_data天赋树→skill_data专属技能→equip_base_data专属装备而且它们之间有严格的 ID 引用关系。设计方案核心挑战是表间 ID 联动——上游表生成的 ID 必须正确传递给下游表。实现为MultiTableGenerator类流程分5步用户需求 → [LLM拆解] → 多表子任务 ↓ [拓扑排序] → 按依赖顺序排列 ↓ [逐表生成] → 上游ID作为下游Prompt上下文 ↓ [批量预览] → 用户确认 ↓ [批量写入] → 多个.txt文件同时更新关键设计决策需求拆解由 LLM 完成给 LLM 完整的表结构和引用关系图让它决定哪些表需要生成数据、每张表生成几条、表间如何关联拓扑排序保证顺序BFS 排序确保被引用表先生成先有角色再有天赋上下文传递前面表生成的完整数据以 JSON 形式注入到后续表的 Prompt 中告诉 LLM “你的 hero_id 字段应引用上面已生成的角色 ID”自动识别多表需求启发式规则检测一整套、“并创造”、配套等信号词以及同时提到多个系统实体角色天赋装备的情况命令行用法# 自动识别多表需求py-3.13data_generator.py-q创建一个新角色亚瑟并为他创造一整套天赋和专属装备# 强制使用跨表模式py-3.13data_generator.py-q...--multi# 强制使用单表模式即使需求看起来是多表的py-3.13data_generator.py-q...--singleWeb UI2026.03为了让非技术人员也能直观理解系统的能力和流程开发了一个科幻风格的 Web 界面。技术选型前端纯 HTML/CSS/JS零依赖科幻暗色主题后端Flask SSEServer-Sent Events流式输出选择不用 Gradio/Streamlit 而用原生 HTML 的原因是对视觉设计有完全控制权。科幻感的核心不是花哨的动画而是信息密度高、层次清晰、反馈即时——这和第一性原理的审美一致。界面设计思路流程条Pipeline Bar顶部的 5 步流程指示器语义检索 → 需求拆解 → LLM 生成 → 数据校验 → 写入文件实时高亮当前步骤让观察者一眼看懂系统在做什么实时日志流通过 SSE 将后端日志实时推送到前端用户能看到每张表的生成进度、ID 分配、校验结果依赖图可视化跨表模式下展示拓扑排序后的生成顺序如buff_data → skill_effect_data → skill_data → hero_base_data数据预览卡片每张生成的表以可折叠卡片展示包含完整的数据表格字段类型用颜色区分ID 青色、数值金色两步确认生成后先预览确认无误再写入文件启动方式py-3.13web_ui.py# 默认 http://127.0.0.1:5000py-3.13web_ui.py--port8080# 指定端口非交互模式命令行运行data_generator.py时系统会在关键节点表选择、写入确认通过input()等待用户输入。但在 Web UI 场景下后台线程没有终端 stdininput()会永久阻塞导致超时。解决方案DataGenerator新增interactive属性默认True。Web UI 在调用生成器前将其设为False此时表选择分数接近时自动选择排名第一的候选表而非等待用户输入写入确认自动确认Web UI 有独立的确认写入按钮实际写入仍由用户在前端控制当前局限与提升方向系统目前能稳定处理正常的数据生成需求但存在以下局限局限1AI 难以理解抽象逻辑和补丁型功能当前系统的核心假设是需求可以直接映射到表结构——用户说加一个角色系统找到hero_base_data表按 Schema 生成数据。但实际策划工作中有大量抽象逻辑需求补丁型功能“把所有火属性技能的伤害提高 20%”——这不是新增数据而是修改已有数据需要理解条件筛选 批量更新当前系统完全不支持跨表条件逻辑“如果角色等级超过 50 级解锁第三套天赋”——这涉及对游戏运行时逻辑的理解LLM 只能看到静态的表结构无法推理运行时行为隐式约束某些字段的合法值取决于其他字段的值如武器类型为 Sword 时攻击速度不能超过 2.0这类约束没有写在 Schema 里LLM 很容易违反提升方向引入表操作类型分类新增 / 修改 / 删除对修改和删除类需求走不同的处理管线将隐式约束以规则或注释的形式写入 Schema 的描述字段。局限2策划需要持续维护字段语义系统的检索和生成质量高度依赖字段描述的准确性。实际运行中发现如果字段描述写得太简略如ID而不是角色唯一标识正整数从1001开始LLM 生成的数据质量会显著下降新增表或新增字段后如果不更新描述、不重建向量库RAG 检索可能找不到或找错枚举值的中文含义没有写在描述里如Const(Sword1,Bow2)没有说明Sword剑, Bow弓LLM 会猜错语义这意味着描述行的维护是一项持续性工作不是建好就不管了。已经在Doc/策划配表规范.md中明确了维护规范但执行层面仍需策划团队的重视。提升方向开发Schema 质量检查工具自动扫描描述为空的字段、没有中文注释的枚举值、描述长度过短的字段生成质量报告提醒策划补全。局限3生成数据仍需人工审核尽管有类型校验、枚举约束、主键唯一性检查等自动校验机制但 LLM 生成的数据在数值合理性层面仍不可完全信赖数值平衡LLM 不了解游戏的数值体系可能生成攻击力 99999这样破坏平衡的数据文案风格技能名称、描述文本的风格可能和已有数据不统一引用一致性跨表联动生成虽然会传递 ID但 LLM 有时会创造性地忽略 Prompt 中的 ID 约束生成不存在的引用所以系统设计了生成-预览-确认写入的两步流程策划必须审核预览数据后才能写入。这不是系统的缺陷而是刻意的设计——AI 是效率工具不是决策替代品。提升方向引入数值范围学习——自动统计已有数据中每个数值字段的分布min/max/avg/std在 Prompt 中约束 LLM 的数值输出范围引入风格一致性检查——用 embedding 相似度检测新生成的文本字段与已有数据的风格差异。局限4本地模型的语义理解上限当前使用的 embedding 模型paraphrase-multilingual-MiniLM-L12-v2只有 12 层384 维对中文的语义理解能力有限对游戏领域的专有名词如元素反应、“词缀”理解不够精准同义词覆盖不足装备和武器的向量距离可能较大需要通过table_aliases.json手动配置别名来弥补提升方向尝试更大的中文 embedding 模型如m3e-base或bge-base-zh或对现有模型做游戏领域的 fine-tune用表名描述别名构造训练对。
自然语言配表 1.0:让策划用一句话生成游戏数据
DEMO演示视频demo演示视频项目背景在游戏开发中策划需要维护大量的配置表格——怪物数据、技能参数、Buff效果、新手引导……这些表格通过专用的表格工具编辑导出为.txt文件再经过导表流程转成 Lua最终由 UE 引擎读取作为数据源。一个典型的.txt文件长这样它可能包含多个 Sheet每个 Sheet 有四行元数据表名、字段名、类型、描述后面跟着成百上千行配置数据字段之间用 Tab 分隔还夹杂着是否导表控制列、终身码行、MergeMark 等各种噪声标记。策划每天要在这些表格里填写、修改数据工作量大且容易出错。我希望做一个AI 驱动的数据中心策划只需用自然语言说给新手引导表增加一条跳过教程的引导系统就能自动找到对应的表、生成符合格式的数据、校验通过后写入文件。实现这个目标需要解决三个核心问题让 AI 理解表格结构——.txt文件格式复杂LLM 无法直接理解让 AI 找到正确的表—— 几十张表用户说新手引导时系统得知道该操作哪张让 AI 生成正确的数据—— 类型要对、枚举值要合法、ID 不能重复下面按这三步详细说说每一环是怎么设计的以及为什么这样做。第一步解析 .txt生成 JSON Schema为什么需要 Schema原始的.txt文件对 LLM 来说就是一堆用 Tab 分隔的文本它无法理解第三列是Int类型、第五列的可选值是Safe/Attention/Monster这些信息。而且一张表动辄几千行全部喂给 LLM 既不现实也没必要。我的方案是把 .txt 的结构信息提取成 JSON Schema。Schema 是一种标准化的数据描述格式包含字段名、类型、描述、枚举值等元信息LLM 天然能理解。解析引擎怎么工作txt_parser.py是整个系统的起点。它的工作流程是拆分 Sheet按**********Sheet:XXX标记将一个.txt文件拆分成多个逻辑表解析四行元数据第一行中文表名如新手引导数据表第二行字段名格式为中文名|英文名如引导ID|guide_id第三行类型定义如Int、String、Const(Safe1,Monster2)、List(Int)等第四行字段描述剥离噪声列自动识别并移除是否导表控制列和终身码列过滤噪声行跳过终身码尾行、MergeMark 行等不含实际数据的行类型映射将导表工具的自定义类型Int、Const(...)、List(List(Int))映射为标准 JSON Schema 类型其中类型映射是比较有意思的部分。导表工具支持嵌套类型比如List(List(Int))表示整数二维列表Const(Safe1,Attention2,Monster3)表示枚举。我用正则模式匹配递归处理这些类型转换成对应的 JSON Schema 表示{type:array,items:{type:array,items:{type:integer}}}数据采样蓄水池算法Schema 里除了结构定义还会带几条真实数据样本examples字段。这些样本有两个作用让 LLM 理解数据的风格和数值范围比如伤害值一般在 50-500 之间在后续的向量检索中样本文本也参与语义匹配采样使用的是蓄水池采样算法Reservoir Sampling。这个算法的妙处在于不需要知道总数据量只需遍历一遍数据就能以等概率抽取 K 条样本。对于几千行的表格不需要全部加载到内存流式处理即可。采样时还会自动过滤是否导表0的行这些行虽然存在于文件中但不会被游戏使用确保样本都是有效数据。引用关系扫描ref_scanner.py负责自动发现表与表之间的外键关系。它用两种策略字段名模式匹配识别xxx_id、xxxID这类后缀与已知表名比对描述文本分析从字段描述中提取索引到 xxx_data、引用 xxx 表等关键信息每条引用标注置信度high/medium/low最终生成一个global_refs.json全局引用关系图。这个信息后续在 RAG 检索时会用到——当用户查询某张表时系统能自动附带上下游关联表的信息。最终产出运行python main.py后output/目录下会生成一系列文件output/ ├── rookie_data.schema.json ← 新手引导数据表的 Schema ├── monster_initial_data.schema.json ← 怪物初始数据表的 Schema ├── ... ← 其他表的 Schema └── global_refs.json ← 全局表间引用关系图每个 Schema 文件大约几十行 JSON精确描述了一张表的完整结构是后续所有 AI 功能的基础。第二步构建向量数据库为什么要向量数据库有了 Schema 文件后下一步是让系统能根据用户的自然语言描述找到对应的表。用户可能说新手引导也可能说Buff持续时间还可能说怪物伤害数据——这些描述和表名之间不是简单的字符串匹配关系需要语义理解。向量数据库的原理是把文本转换成高维向量embedding语义相近的文本在向量空间中距离相近。当用户输入查询时也转换成向量然后找出距离最近的几条记录。选型本地模型 ChromaDB考虑到这是公司内部工具我选择了完全本地化的方案Embedding 模型sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2一个支持 50 语言的多语言句向量模型12 层 MiniLM 架构轻量且对中文有不错的效果运行在本地 CPU 上向量数据库ChromaDB轻量级的嵌入式向量数据库数据存储在本地chroma_db/目录无需部署服务选择本地模型而非调用远程 API 做 embedding主要考虑策划的操作频率高每次检索都调远程 API 太慢embedding 质量对中文表名的匹配效果影响很大需要能控制和调优离线环境也要能用两个 Collection 的设计vector_store_builder.py构建了两个独立的 Collectionschema_index表级别的语义文档。每个 Schema 被转化为一段自然语言描述包含表名、中文名、字段列表、字段描述等。用于用户说了什么 → 哪张表最相关的检索。sample_index样本级别的文档。每条样本数据也被索引这样当用户描述具体的数据特征时如持续10秒的Buff能通过样本内容匹配到对应的表。两个 Collection 各司其职后续检索时分别查询、综合打分。文档构造的细节Schema 语义文档不是简单地把 JSON dump 进去而是精心构造的自然语言文本表名: rookie_data 描述: 游戏配置表 [新手引导数据表]rookie_data 中文名: 新手引导数据表 来源文件: 新手引导表.txt 共 15 个字段: - guide_id引导ID类型: Int - guide_name引导名称类型: String - trigger_type触发类型类型: Const(...)可选值: Enter, Click, Auto ...这样做是因为 embedding 模型是在自然语言上训练的给它看的文本越像自然语言生成的向量质量越高。第三步RAG 检索 LLM 生成 写入这是整个系统最核心的一步也是踩坑最多的一步。用户输入一句话系统需要完成检索 → 生成 → 校验 → 写入。3.1 RAG 检索混合策略纯语义检索有一个严重问题中文表名的精确匹配做不好。比如用户输入给新手引导表加一条数据“新手引导这四个字明确指向了rookie_data表。但 embedding 模型可能认为新手引导和新手教程”、引导奖励的语义距离差不多导致rookie_data排名不高。我的解决方案是三路混合检索1中文关键词匹配_keyword_match()方法从用户输入中提取中文关键词与每张表的中文名、来源文件名进行匹配。匹配策略按分数从高到低策略分数示例输入包含完整中文表名0.95“给新手引导表加数据”关键词与表名核心词互含0.90“新手引导” ↔ “新手引导数据表”别名匹配配置文件0.92“新手” → rookie_data别名配置模块关键词匹配0.70“引导” → 引导模块下所有表别名和模块可以在table_aliases.json中自由配置应对策划口语化的表述。2Schema 语义搜索 样本语义搜索同时查询 schema_index 和 sample_index 两个 Collection获取语义层面最相关的表。3分数融合——保底机制三路结果合并后需要一个统一的打分公式。最初的设计是简单加权最终分 关键词分×0.5 Schema语义分×0.35 样本语义分×0.15但实际测试中发现一个严重问题当关键词精确匹配了某张表分数 0.92但这张表恰好没被语义搜索命中Schema 分 0、样本分 0加权后变成了0.92×0.5 0.46反而排在了语义搜索命中的其他表后面这就是所谓的高置信度关键词被低权重稀释的问题。修复方案是加一个保底机制ifkw_score0:weightedkw_score*0.5schema_score*0.35sample_score*0.15final_scoremax(weighted,kw_score)# 关键词分数保底逻辑很简单如果用户输入明确提到了某张表的名字那这张表的最终得分至少不应该低于关键词匹配本身的分数。这个小改动让检索准确率从大约 70% 提升到了 95% 以上。3.2 LLM 数据生成检索到目标表后系统将 Schema字段定义、类型、枚举值、样本数据、用户需求组装成 Prompt发给 Claude API因为工作室有免费的Claude API和gemini APIgemini经常占线所以选用Claude并非不可替换 生成结构化数据。ID 分配代码驱动而非 LLM 决定早期设计中我在 Prompt 里告诉 LLM已有 ID 列表让它自己生成不重复的新 ID。但实际运行中遇到了严重问题一张表可能有上万个已有 IDPrompt 里只能展示前 20 个LLM 生成的 ID 经常和未展示的那些 ID 冲突校验失败后反复重试也解决不了失败率大幅提升还会浪费大量token。最终方案是把 ID 分配从 LLM 手中拿走完全由 Python 代码控制defcompute_next_ids(existing_ids,count):# 找到已有 ID 的最大值从 max1 开始分配startmax(existing_ids)1returnlist(range(start,startcount))Prompt 里直接告诉 LLM“主键 ID 已由系统分配请使用以下 ID[751, 752, 753]”。生成后还会强制回填——不管 LLM 返回了什么 ID都用代码计算的 ID 覆盖fori,rowinenumerate(rows):row[pk_field]assigned_ids[i]这是一个重要的设计原则凡是有确定性答案的事情就不要交给 LLM 去猜。ID 的正确性可以通过简单的代码逻辑 100% 保证没必要依赖 LLM 的概率输出。自然语言解析生成条数用户可能说加3条新数据也可能说增加一条引导。_parse_row_count()用正则从输入中提取数量阿拉伯数字(\d)\s*[条个行]→ “3条” 3中文数字([一二两三四五六七八九十])\s*[条个行]→ “一条” 1默认值如果没有提到数量默认生成 1 条上限保护最多 50 条防止意外3.3 数据校验LLM 生成的数据在写入前必须经过严格校验校验项说明类型检查Int 字段必须是整数Float 必须是数值Bool 必须是 0/1枚举约束Const(Safe1,Monster2)字段只能使用定义内的值必填检查required 字段不能为空主键唯一性ID 不能与已有数据重复数组格式List(Int)字段必须是合法的数组格式校验失败后错误信息会反馈给 LLM 重新生成最多重试 2 次。这个生成-校验-反馈-重试的循环能有效提高数据质量。3.4 安全写入最后一步是把生成的数据写入.txt文件。txt_writer.py负责这项工作几个关键设计定位插入点新数据插入到目标 Sheet 的终身码行之前终身码行是每个 Sheet 的最后一行特殊标记是导表工具管线特有的机制并非通用机制格式化按字段顺序拼接 Tab 分隔行首列补是否导表标记末列自动生成 9 位终身码编码保持检测原文件编码可能是 UTF-8、GBK 等写入时保持一致否则导表工具无法识别原子写入先写到临时文件再 rename 替换原文件防止写入中途崩溃导致文件损坏整体数据流策划的 .txt 文件 ↓ txt_parser.py结构解析 噪声过滤 ↓ data_sampler.py蓄水池采样 ↓ ref_scanner.py引用关系识别 output/*.schema.json global_refs.json ↓ vector_store_builder.py文档构造 Embedding chroma_db/schema_index sample_index ↓ rag_query.py关键词 语义混合检索 保底分融合 ↓ data_generator.pyPrompt 组装 Claude API 代码 ID 分配 ↓ DataValidator类型/枚举/主键校验 ↓ txt_writer.py格式化 终身码 原子写入 写入完成的 .txt 文件实际效果策划输入“给新手引导表增加一条跳过教程的引导”系统执行RAG 检索 →rookie_data92% 关键词匹配自动选择读取已有 750 条数据分配 ID 751调用 Claude 生成一条符合 Schema 的引导数据校验通过类型正确、枚举值合法、ID 唯一写入新手引导表.txt输出变更摘要整个过程约 5 秒策划无需了解表格结构的任何细节。踩过的坑关键词高分被加权稀释上文已述保底机制解决LLM 生成重复 IDPrompt 只展示部分 IDLLM 无法避开全部已有 ID → 改为代码分配embedding 模型对中文表名不敏感纯语义检索对新手引导这类专有名词效果差 → 加入关键词匹配作为补充文件编码不一致写入时不保持原编码会导致导表工具报错 → 写入前检测并保持编码终身码冲突新生成的 9 位终身码可能和已有的冲突 → 生成后全局去重每个坑都对应着代码中的一个具体修复这也是工程和理论的区别——论文里的 RAG 流程图很简洁真正落地时 80% 的工作量都在处理这些边界情况。测试数据重构与RAG验证2026.03为什么重构测试数据之前的测试数据新手引导表、tips弹窗表等过于简单字段少、表间引用稀疏无法充分验证系统在复杂表结构下的表现。于是设计了一套更贴近真实游戏项目的测试数据5个文件、18张表、覆盖角色/技能/Buff/装备/关卡/道具六大系统刻意制造了密集的跨表引用关系。新测试数据设计文件表核心设计意图角色相关表.txthero_base_data, hero_growth_data, hero_talent_data角色基础→成长→天赋的三层引用链技能与Buff表.txtskill_data, skill_effect_data, skill_upgrade_data, buff_data, buff_trigger_data, element_reaction_data技能→效果→Buff的密集交叉引用装备系统表.txtequip_base_data, equip_affix_data, equip_set_data, enhance_cost_data装备→词缀→套装→强化的完整装备链关卡与掉落表.txtstage_config_data, wave_data, drop_group_data, drop_item_data关卡→波次→掉落组→掉落物的四层级联道具总表.txtitem_base_data被多张表引用的基础道具表全链路重建结果Schema生成18张表全部正确解析字段类型、枚举值、描述信息准确引用扫描RefScanner检出41条引用关系33高置信、4中、4低跨文件引用网络与设计完全吻合向量库构建ChromaDB两个集合共107条文档18条表级 89条样本级构建耗时25秒语义搜索准确率测试用12条中文自然语言查询做端到端测试覆盖直接别名、领域术语、模糊描述等场景给角色表加一个新角色 → hero_base_data ✓ (0.920) 增加一个火属性的技能 → skill_data ✓ (0.750) 加一条持续伤害的Buff → buff_data ✓ (0.700) 给装备表增加一把新武器 → equip_base_data ✓ (0.920) 添加一个新关卡 → stage_config_data ✓ (0.920) 增加一条掉落配置 → drop_group_data ✓ (0.920) 加一个新道具 → item_base_data ✓ (0.700) 元素反应水火蒸发 → element_reaction_data ✓ (0.920) 角色天赋 → hero_talent_data ✓ (0.920) 装备套装效果 → equip_set_data ✓ (0.920) 技能升级消耗 → skill_upgrade_data ✓ (0.920) 角色突破升级 → hero_growth_data ✓ (0.773)最终准确率12/12 100%关键发现关键词匹配 语义向量的混合策略非常有效精确别名匹配贡献了0.920的保底高分语义向量负责兜底模糊查询table_aliases.json的模块分组帮助把关卡这类泛化查询正确路由到stage_config_data而非同模块的drop_group_data引用密度影响检索enhance_cost_data和drop_item_data因为被多表引用在多个查询中以第二名出现说明引用关系权重在排序中发挥了作用跨表联动生成2026.03为什么需要跨表联动单表生成能力已经稳定了但真实策划需求往往是跨表的“创建一个新角色亚瑟并为他创造一整套天赋和专属装备设计方案以王者荣耀的亚瑟为模板”这一句话涉及hero_base_data新角色→hero_growth_data成长曲线→hero_talent_data天赋树→skill_data专属技能→equip_base_data专属装备而且它们之间有严格的 ID 引用关系。设计方案核心挑战是表间 ID 联动——上游表生成的 ID 必须正确传递给下游表。实现为MultiTableGenerator类流程分5步用户需求 → [LLM拆解] → 多表子任务 ↓ [拓扑排序] → 按依赖顺序排列 ↓ [逐表生成] → 上游ID作为下游Prompt上下文 ↓ [批量预览] → 用户确认 ↓ [批量写入] → 多个.txt文件同时更新关键设计决策需求拆解由 LLM 完成给 LLM 完整的表结构和引用关系图让它决定哪些表需要生成数据、每张表生成几条、表间如何关联拓扑排序保证顺序BFS 排序确保被引用表先生成先有角色再有天赋上下文传递前面表生成的完整数据以 JSON 形式注入到后续表的 Prompt 中告诉 LLM “你的 hero_id 字段应引用上面已生成的角色 ID”自动识别多表需求启发式规则检测一整套、“并创造”、配套等信号词以及同时提到多个系统实体角色天赋装备的情况命令行用法# 自动识别多表需求py-3.13data_generator.py-q创建一个新角色亚瑟并为他创造一整套天赋和专属装备# 强制使用跨表模式py-3.13data_generator.py-q...--multi# 强制使用单表模式即使需求看起来是多表的py-3.13data_generator.py-q...--singleWeb UI2026.03为了让非技术人员也能直观理解系统的能力和流程开发了一个科幻风格的 Web 界面。技术选型前端纯 HTML/CSS/JS零依赖科幻暗色主题后端Flask SSEServer-Sent Events流式输出选择不用 Gradio/Streamlit 而用原生 HTML 的原因是对视觉设计有完全控制权。科幻感的核心不是花哨的动画而是信息密度高、层次清晰、反馈即时——这和第一性原理的审美一致。界面设计思路流程条Pipeline Bar顶部的 5 步流程指示器语义检索 → 需求拆解 → LLM 生成 → 数据校验 → 写入文件实时高亮当前步骤让观察者一眼看懂系统在做什么实时日志流通过 SSE 将后端日志实时推送到前端用户能看到每张表的生成进度、ID 分配、校验结果依赖图可视化跨表模式下展示拓扑排序后的生成顺序如buff_data → skill_effect_data → skill_data → hero_base_data数据预览卡片每张生成的表以可折叠卡片展示包含完整的数据表格字段类型用颜色区分ID 青色、数值金色两步确认生成后先预览确认无误再写入文件启动方式py-3.13web_ui.py# 默认 http://127.0.0.1:5000py-3.13web_ui.py--port8080# 指定端口非交互模式命令行运行data_generator.py时系统会在关键节点表选择、写入确认通过input()等待用户输入。但在 Web UI 场景下后台线程没有终端 stdininput()会永久阻塞导致超时。解决方案DataGenerator新增interactive属性默认True。Web UI 在调用生成器前将其设为False此时表选择分数接近时自动选择排名第一的候选表而非等待用户输入写入确认自动确认Web UI 有独立的确认写入按钮实际写入仍由用户在前端控制当前局限与提升方向系统目前能稳定处理正常的数据生成需求但存在以下局限局限1AI 难以理解抽象逻辑和补丁型功能当前系统的核心假设是需求可以直接映射到表结构——用户说加一个角色系统找到hero_base_data表按 Schema 生成数据。但实际策划工作中有大量抽象逻辑需求补丁型功能“把所有火属性技能的伤害提高 20%”——这不是新增数据而是修改已有数据需要理解条件筛选 批量更新当前系统完全不支持跨表条件逻辑“如果角色等级超过 50 级解锁第三套天赋”——这涉及对游戏运行时逻辑的理解LLM 只能看到静态的表结构无法推理运行时行为隐式约束某些字段的合法值取决于其他字段的值如武器类型为 Sword 时攻击速度不能超过 2.0这类约束没有写在 Schema 里LLM 很容易违反提升方向引入表操作类型分类新增 / 修改 / 删除对修改和删除类需求走不同的处理管线将隐式约束以规则或注释的形式写入 Schema 的描述字段。局限2策划需要持续维护字段语义系统的检索和生成质量高度依赖字段描述的准确性。实际运行中发现如果字段描述写得太简略如ID而不是角色唯一标识正整数从1001开始LLM 生成的数据质量会显著下降新增表或新增字段后如果不更新描述、不重建向量库RAG 检索可能找不到或找错枚举值的中文含义没有写在描述里如Const(Sword1,Bow2)没有说明Sword剑, Bow弓LLM 会猜错语义这意味着描述行的维护是一项持续性工作不是建好就不管了。已经在Doc/策划配表规范.md中明确了维护规范但执行层面仍需策划团队的重视。提升方向开发Schema 质量检查工具自动扫描描述为空的字段、没有中文注释的枚举值、描述长度过短的字段生成质量报告提醒策划补全。局限3生成数据仍需人工审核尽管有类型校验、枚举约束、主键唯一性检查等自动校验机制但 LLM 生成的数据在数值合理性层面仍不可完全信赖数值平衡LLM 不了解游戏的数值体系可能生成攻击力 99999这样破坏平衡的数据文案风格技能名称、描述文本的风格可能和已有数据不统一引用一致性跨表联动生成虽然会传递 ID但 LLM 有时会创造性地忽略 Prompt 中的 ID 约束生成不存在的引用所以系统设计了生成-预览-确认写入的两步流程策划必须审核预览数据后才能写入。这不是系统的缺陷而是刻意的设计——AI 是效率工具不是决策替代品。提升方向引入数值范围学习——自动统计已有数据中每个数值字段的分布min/max/avg/std在 Prompt 中约束 LLM 的数值输出范围引入风格一致性检查——用 embedding 相似度检测新生成的文本字段与已有数据的风格差异。局限4本地模型的语义理解上限当前使用的 embedding 模型paraphrase-multilingual-MiniLM-L12-v2只有 12 层384 维对中文的语义理解能力有限对游戏领域的专有名词如元素反应、“词缀”理解不够精准同义词覆盖不足装备和武器的向量距离可能较大需要通过table_aliases.json手动配置别名来弥补提升方向尝试更大的中文 embedding 模型如m3e-base或bge-base-zh或对现有模型做游戏领域的 fine-tune用表名描述别名构造训练对。