[{"data":1,"prerenderedAt":1434},["ShallowReactive",2],{"post-chinese-poetry-rag":3,"post-nav-posts":1102,"post-project-chinese-poetry-rag":1126},{"id":4,"title":5,"body":6,"cover":965,"date":1089,"description":49,"extension":1090,"links":1091,"meta":1092,"navigation":163,"path":1093,"project":1053,"seo":1094,"slug":1095,"stem":1096,"summary":1097,"tags":1098,"visible":163,"__hash__":1101},"posts\u002Fposts\u002Fchinese-poetry-rag.md","用 RAG + FAISS 构建古诗词 AI 取名系统：从向量检索到六层质量过滤",{"type":7,"value":8,"toc":1059},"minimark",[9,31,36,39,50,53,131,135,140,143,194,197,201,204,210,216,219,328,331,337,341,344,351,410,413,417,421,424,430,433,440,448,454,465,468,522,529,656,659,662,727,734,738,741,745,754,757,761,764,768,771,786,790,793,821,824,828,831,838,841,871,875,878,881,885,889,892,899,903,906,909,929,933,936,940,953,959,966,972,978,984,989,995,1001,1006,1009,1013,1019,1022,1025,1028,1031,1034,1045,1048,1055],[10,11,12,21,24],"blockquote",{},[13,14,15,16,20],"p",{},"用 LLM 生成古诗词名字，最大的问题不是\"好不好听\"，而是",[17,18,19],"strong",{},"它会编造出处","。",[13,22,23],{},"让大模型给你推荐一个出自《诗经》的名字，它大概率会自信满满地给你一个假的诗句、假的篇名、假的释义。这不是模型能力问题，而是幻觉的结构性根源——它没有引用真实语料的机制。",[13,25,26,27,30],{},"所以我做了一个系统：",[17,28,29],{},"每个名字都必须来自真实可检索的古诗词原文","，通过 RAG（检索增强生成）架构强制约束。以下是完整的技术拆解。",[32,33,35],"h2",{"id":34},"一架构全景","一、架构全景",[13,37,38],{},"先看整体数据流：",[40,41,46],"pre",{"className":42,"code":44,"language":45},[43],"language-text","用户输入                      离线预处理\n─────────                    ──────────\n姓氏+性别+出生时间      270万句古诗词原文\n     │                        │\n     ▼                        ▼\n 八字计算 → 五行分析      繁→简转换(OpenCC)\n     │          │            句子切分(≥4字)\n     │     喜用元素           负面意象过滤\n     │          │            │\n     │     映射意象关键词     │\n     │          │            │\n     ▼          ▼            ▼\n  拼接搜索query         Embedding向量化\n     │          │            │\n     ▼          │            ▼\n  Query向量化   │       FAISS索引(525MB)\n     │          │            │\n     └────┬─────┘            │\n          ▼                  │\n   Top-K相似检索 ◄───────────┘\n          │\n          ▼\n   候选诗句池(50首)\n          │\n          ▼\n   LLM Prompt生成(严格约束不许编造)\n          │\n          ▼\n   流式输出 → SSE → 前端逐个渲染\n          │\n          ▼\n   六层质量过滤\n   ┌─────────────────────────────┐\n   │ 1. 烂大街字黑名单             │\n   │ 2. 谐音梗检测                │\n   │ 3. 生僻字过滤                │\n   │ 4. 音韵评分(pypinyin)        │\n   │ 5. 五格数理(81数理吉凶)       │\n   │ 6. 历史去重                  │\n   └─────────────────────────────┘\n          │\n          ▼\n     最终名字 + 诗词出处 + 完整解析\n","text",[47,48,44],"code",{"__ignoreMap":49},"",[13,51,52],{},"技术选型一览：",[54,55,56,72],"table",{},[57,58,59],"thead",{},[60,61,62,66,69],"tr",{},[63,64,65],"th",{},"环节",[63,67,68],{},"选择",[63,70,71],{},"理由",[73,74,75,87,98,109,120],"tbody",{},[60,76,77,81,84],{},[78,79,80],"td",{},"向量化",[78,82,83],{},"Zhipu Embedding-3",[78,85,86],{},"中文语义理解能力强，1024 维",[60,88,89,92,95],{},[78,90,91],{},"向量检索",[78,93,94],{},"FAISS（本地）",[78,96,97],{},"无外部依赖，支持 mmap 加载",[60,99,100,103,106],{},[78,101,102],{},"LLM",[78,104,105],{},"DeepSeek-V4",[78,107,108],{},"中文能力强，OpenAI 兼容 API",[60,110,111,114,117],{},[78,112,113],{},"元数据",[78,115,116],{},"SQLite + JSON 双备",[78,118,119],{},"轻量，WAL 模式支持并发读",[60,121,122,125,128],{},[78,123,124],{},"流式协议",[78,126,127],{},"SSE",[78,129,130],{},"比 WebSocket 简单，单向推送够用",[32,132,134],{"id":133},"二向量检索-域知识注入","二、向量检索 + 域知识注入",[136,137,139],"h3",{"id":138},"_21-基础检索","2.1 基础检索",[13,141,142],{},"古诗词语料经过预处理后（繁→简转换、按句切分、负面过滤），通过 Embedding-3 向量化存入 FAISS 索引。查询时，将用户需求编码为自然语言：",[40,144,148],{"className":145,"code":146,"language":147,"meta":49,"style":49},"language-python shiki shiki-themes github-dark github-light","query = f\"姓氏：{surname}，性别：{gender}，风格：古典诗词，意境优美\"\n\nquery_vec = embedding_client.embed(query)\nfaiss.normalize_L2(query_vec)  # L2归一化 → 等价余弦相似度\n_, indices = index.search(query_vec, k=50)\n\ncandidates = [metadata[i] for i in indices[0]]\n","python",[47,149,150,158,165,171,177,183,188],{"__ignoreMap":49},[151,152,155],"span",{"class":153,"line":154},"line",1,[151,156,157],{},"query = f\"姓氏：{surname}，性别：{gender}，风格：古典诗词，意境优美\"\n",[151,159,161],{"class":153,"line":160},2,[151,162,164],{"emptyLinePlaceholder":163},true,"\n",[151,166,168],{"class":153,"line":167},3,[151,169,170],{},"query_vec = embedding_client.embed(query)\n",[151,172,174],{"class":153,"line":173},4,[151,175,176],{},"faiss.normalize_L2(query_vec)  # L2归一化 → 等价余弦相似度\n",[151,178,180],{"class":153,"line":179},5,[151,181,182],{},"_, indices = index.search(query_vec, k=50)\n",[151,184,186],{"class":153,"line":185},6,[151,187,164],{"emptyLinePlaceholder":163},[151,189,191],{"class":153,"line":190},7,[151,192,193],{},"candidates = [metadata[i] for i in indices[0]]\n",[13,195,196],{},"用自然语言而非关键词拼接，是因为 Embedding-3 对语义的理解远比关键词匹配准确。\"意境优美的古诗词\"这样的描述，能检索到包含山水、清风、明月等意象的诗句，而关键词\"优美\"本身可能一句都匹配不上。",[136,198,200],{"id":199},"_22-八字五行-向量偏移","2.2 八字五行 → 向量偏移",[13,202,203],{},"这是整个系统最独特的设计。传统取名软件的五行补救，是推荐固定偏旁（缺水带\"氵\"，缺木带\"木\"）。但古诗词取名不能这样做——你不能限制用户只能用带\"氵\"的字。",[13,205,206,207,20],{},"我的方案是：",[17,208,209],{},"把五行喜用转化为古诗意象关键词，注入 FAISS 检索 query，让向量检索自然偏移到含对应意象的诗句",[40,211,214],{"className":212,"code":213,"language":45},[43],"出生时间\n  │\n  ▼\n四柱八字(年月日时 → 天干地支)\n  │\n  ▼\n十神分析 → 日主强弱 → 旺衰法\n  │\n  ▼\n喜用神 → 意象关键词映射\n  │\n  ▼          五行 → 意象关键词\n  │         ──────────────────────\n  │          水 → \"雨 云 河 溪 澜 泉 润\"\n  │          木 → \"林 松 竹 兰 芳 蕊\"\n  │          金 → \"玉 银 锋 铭 锐 钰\"\n  │          火 → \"日 炎 晖 曜 煜 烨\"\n  │          土 → \"山 岳 峰 坤 垣 培\"\n  ▼\n注入检索query → 偏移到含对应意象的古诗\n",[47,215,213],{"__ignoreMap":49},[13,217,218],{},"核心代码：",[40,220,222],{"className":145,"code":221,"language":147,"meta":49,"style":49},"WUXING_KEYWORDS = {\n    \"金\": [\"玉\", \"银\", \"锋\", \"铭\", \"锐\", \"钰\", \"鑫\"],\n    \"木\": [\"林\", \"松\", \"竹\", \"兰\", \"芳\", \"蕊\", \"萱\"],\n    \"水\": [\"雨\", \"云\", \"河\", \"溪\", \"澜\", \"泉\", \"润\"],\n    \"火\": [\"日\", \"炎\", \"晖\", \"曜\", \"煜\", \"烨\", \"灿\"],\n    \"土\": [\"山\", \"岳\", \"峰\", \"坤\", \"垣\", \"培\", \"城\"],\n}\n\ndef build_query(surname, gender, favored_elements):\n    \"\"\"将五行喜用映射为古诗意象，注入检索query\"\"\"\n    base = f\"姓氏：{surname}，性别：{gender}，风格：古典诗词\"\n\n    imagery = []\n    for elem in favored_elements:\n        imagery.extend(WUXING_KEYWORDS[elem][:3])\n\n    if imagery:\n        return f\"{base}，意象：{' '.join(imagery)}\"\n    return base\n",[47,223,224,229,234,239,244,249,254,259,264,270,276,282,287,293,299,305,310,316,322],{"__ignoreMap":49},[151,225,226],{"class":153,"line":154},[151,227,228],{},"WUXING_KEYWORDS = {\n",[151,230,231],{"class":153,"line":160},[151,232,233],{},"    \"金\": [\"玉\", \"银\", \"锋\", \"铭\", \"锐\", \"钰\", \"鑫\"],\n",[151,235,236],{"class":153,"line":167},[151,237,238],{},"    \"木\": [\"林\", \"松\", \"竹\", \"兰\", \"芳\", \"蕊\", \"萱\"],\n",[151,240,241],{"class":153,"line":173},[151,242,243],{},"    \"水\": [\"雨\", \"云\", \"河\", \"溪\", \"澜\", \"泉\", \"润\"],\n",[151,245,246],{"class":153,"line":179},[151,247,248],{},"    \"火\": [\"日\", \"炎\", \"晖\", \"曜\", \"煜\", \"烨\", \"灿\"],\n",[151,250,251],{"class":153,"line":185},[151,252,253],{},"    \"土\": [\"山\", \"岳\", \"峰\", \"坤\", \"垣\", \"培\", \"城\"],\n",[151,255,256],{"class":153,"line":190},[151,257,258],{},"}\n",[151,260,262],{"class":153,"line":261},8,[151,263,164],{"emptyLinePlaceholder":163},[151,265,267],{"class":153,"line":266},9,[151,268,269],{},"def build_query(surname, gender, favored_elements):\n",[151,271,273],{"class":153,"line":272},10,[151,274,275],{},"    \"\"\"将五行喜用映射为古诗意象，注入检索query\"\"\"\n",[151,277,279],{"class":153,"line":278},11,[151,280,281],{},"    base = f\"姓氏：{surname}，性别：{gender}，风格：古典诗词\"\n",[151,283,285],{"class":153,"line":284},12,[151,286,164],{"emptyLinePlaceholder":163},[151,288,290],{"class":153,"line":289},13,[151,291,292],{},"    imagery = []\n",[151,294,296],{"class":153,"line":295},14,[151,297,298],{},"    for elem in favored_elements:\n",[151,300,302],{"class":153,"line":301},15,[151,303,304],{},"        imagery.extend(WUXING_KEYWORDS[elem][:3])\n",[151,306,308],{"class":153,"line":307},16,[151,309,164],{"emptyLinePlaceholder":163},[151,311,313],{"class":153,"line":312},17,[151,314,315],{},"    if imagery:\n",[151,317,319],{"class":153,"line":318},18,[151,320,321],{},"        return f\"{base}，意象：{' '.join(imagery)}\"\n",[151,323,325],{"class":153,"line":324},19,[151,326,327],{},"    return base\n",[13,329,330],{},"为什么不直接用关键词过滤（\"包含'水'字的诗句\"）？因为\"水\"的意象远不止字面包含\"水\"的诗句。\"落霞与孤鹜齐飞，秋水共长天一色\"里\"水\"不是主角，但整体意象是水。Embedding-3 能捕捉这种语义关联，关键词过滤做不到。",[13,332,333,336],{},[17,334,335],{},"实测效果","：缺水的八字，注入\"雨 云 河 溪\"后，检索到的候选诗句中含水意象的比例从 15% 提升到 60% 以上。向量检索确实会往对应意象偏移。",[136,338,340],{"id":339},"_23-换一批时的多样性策略","2.3 换一批时的多样性策略",[13,342,343],{},"用户点\"换一批\"时，不能简单地再跑一次同样的检索——大概率会得到相似的结果。",[13,345,346,347,350],{},"解决方案是",[17,348,349],{},"方向词轮转","：维护一组主题方向，每次换一批切换一个，让 FAISS 检索偏移到不同诗歌集群。",[40,352,354],{"className":145,"code":353,"language":147,"meta":49,"style":49},"DIRECTION_WORDS = [\n    \"山水田园\", \"日月星辰\", \"花鸟鱼虫\",\n    \"德行修养\", \"志向抱负\", \"清雅温婉\"\n]\n\ndef rotate_query(base_query, used_directions):\n    \"\"\"换一批时切换意象方向，保证每轮结果不同\"\"\"\n    available = [d for d in DIRECTION_WORDS if d not in used_directions]\n    direction = random.choice(available)\n    used_directions.append(direction)\n    return f\"{base_query}，主题方向：{direction}\"\n",[47,355,356,361,366,371,376,380,385,390,395,400,405],{"__ignoreMap":49},[151,357,358],{"class":153,"line":154},[151,359,360],{},"DIRECTION_WORDS = [\n",[151,362,363],{"class":153,"line":160},[151,364,365],{},"    \"山水田园\", \"日月星辰\", \"花鸟鱼虫\",\n",[151,367,368],{"class":153,"line":167},[151,369,370],{},"    \"德行修养\", \"志向抱负\", \"清雅温婉\"\n",[151,372,373],{"class":153,"line":173},[151,374,375],{},"]\n",[151,377,378],{"class":153,"line":179},[151,379,164],{"emptyLinePlaceholder":163},[151,381,382],{"class":153,"line":185},[151,383,384],{},"def rotate_query(base_query, used_directions):\n",[151,386,387],{"class":153,"line":190},[151,388,389],{},"    \"\"\"换一批时切换意象方向，保证每轮结果不同\"\"\"\n",[151,391,392],{"class":153,"line":261},[151,393,394],{},"    available = [d for d in DIRECTION_WORDS if d not in used_directions]\n",[151,396,397],{"class":153,"line":266},[151,398,399],{},"    direction = random.choice(available)\n",[151,401,402],{"class":153,"line":272},[151,403,404],{},"    used_directions.append(direction)\n",[151,406,407],{"class":153,"line":278},[151,408,409],{},"    return f\"{base_query}，主题方向：{direction}\"\n",[13,411,412],{},"\"山水田园\"会偏移到王维、孟浩然的诗句；\"日月星辰\"则偏向李白、苏轼。每轮结果自然不同。",[32,414,416],{"id":415},"三prompt-工程与流式解析","三、Prompt 工程与流式解析",[136,418,420],{"id":419},"_31-约束-llm-不编造出处","3.1 约束 LLM 不编造出处",[13,422,423],{},"Prompt 设计中最关键的约束：",[40,425,428],{"className":426,"code":427,"language":45},[43],"【硬约束】只能使用上述提供的诗句原文，绝不编造任何诗句、出处或释义。\n         如果候选诗句中没有合适的，宁可少生成一个名字，也不许杜撰。\n\n【跨诗规则】名字的每个字必须来自不同诗句。\n            最多一个字来自同一首诗，以保证文化关联的丰富性。\n\n【格式要求】使用 \u003C\u003CNAME>> 分隔符逐个输出每个名字，\n            每个名字包含：名字、出处、诗句原文、释义、思考过程\n",[47,429,427],{"__ignoreMap":49},[13,431,432],{},"跨诗规则是容易忽略但很重要的设计——如果两个字来自同一首诗，名字的文化厚度就局限在一首诗里。跨诗取字让每个名字有多重文化关联，解释空间更大。",[13,434,435,436,439],{},"但即使有严格的 prompt 约束，LLM 仍然可能编造。所以还需要",[17,437,438],{},"后处理校验","：把 LLM 引用的诗句在原文库里做精确匹配，不匹配的直接丢弃，触发重新生成。两道防线确保零编造。",[136,441,443,444],{"id":442},"_32-流式解析","3.2 \u003C",[445,446,447],"name",{},"> 流式解析",[13,449,450,451,20],{},"LLM 流式输出最大的工程挑战是：",[17,452,453],{},"输出中途不是合法的 JSON",[13,455,456,457,460,461,464],{},"假设 LLM 要输出 ",[47,458,459],{},"{\"names\": [{\"name\": \"清涵\"}, ...]}","，在流式传输过程中，你收到的前几个 chunk 可能是 ",[47,462,463],{},"{\"names\": [{\"name\": \"清","——这不是合法 JSON，无法解析。",[13,466,467],{},"常见方案对比：",[54,469,470,483],{},[57,471,472],{},[60,473,474,477,480],{},[63,475,476],{},"方案",[63,478,479],{},"优点",[63,481,482],{},"缺点",[73,484,485,496,507],{},[60,486,487,490,493],{},[78,488,489],{},"等完整输出再解析",[78,491,492],{},"实现简单",[78,494,495],{},"失去流式意义，延迟高",[60,497,498,501,504],{},[78,499,500],{},"JSON 流式解析器",[78,502,503],{},"能增量解析",[78,505,506],{},"复杂、脆弱、LLM 输出风格微变就挂",[60,508,509,514,519],{},[78,510,511],{},[17,512,513],{},"自定义分隔符",[78,515,516],{},[17,517,518],{},"简单、通用、零依赖",[78,520,521],{},"需要在 prompt 里约定格式",[13,523,524,525,528],{},"我选了自定义分隔符方案。Prompt 要求 LLM 用 ",[47,526,527],{},"\u003C\u003CNAME>>"," 作为名字之间的分隔标记，解析端只需按这个标记切分缓冲区：",[40,530,532],{"className":145,"code":531,"language":147,"meta":49,"style":49},"async def stream_names(llm_stream):\n    \"\"\"从LLM流中增量解析每个名字块\"\"\"\n    buffer = \"\"\n    async for chunk in llm_stream:\n        buffer += chunk\n        # 每发现一个\u003C\u003CNAME>>标记，就切出一个完整的名字块\n        while \"\u003C\u003CNAME>>\" in buffer:\n            block, buffer = buffer.split(\"\u003C\u003CNAME>>\", 1)\n            if block.strip():\n                yield parse_name_block(block)\n\n    # 最后一个块没有后续\u003C\u003CNAME>>标记，单独处理\n    if buffer.strip():\n        yield parse_name_block(buffer)\n\n\ndef parse_name_block(text):\n    \"\"\"从名字块中提取结构化数据\"\"\"\n    result = {}\n    for line in text.strip().split(\"\\n\"):\n        if \"：\" in line:\n            key, value = line.split(\"：\", 1)\n            result[key.strip()] = value.strip()\n    return result\n",[47,533,534,539,544,549,554,559,564,569,574,579,584,588,593,598,603,607,611,616,621,626,632,638,644,650],{"__ignoreMap":49},[151,535,536],{"class":153,"line":154},[151,537,538],{},"async def stream_names(llm_stream):\n",[151,540,541],{"class":153,"line":160},[151,542,543],{},"    \"\"\"从LLM流中增量解析每个名字块\"\"\"\n",[151,545,546],{"class":153,"line":167},[151,547,548],{},"    buffer = \"\"\n",[151,550,551],{"class":153,"line":173},[151,552,553],{},"    async for chunk in llm_stream:\n",[151,555,556],{"class":153,"line":179},[151,557,558],{},"        buffer += chunk\n",[151,560,561],{"class":153,"line":185},[151,562,563],{},"        # 每发现一个\u003C\u003CNAME>>标记，就切出一个完整的名字块\n",[151,565,566],{"class":153,"line":190},[151,567,568],{},"        while \"\u003C\u003CNAME>>\" in buffer:\n",[151,570,571],{"class":153,"line":261},[151,572,573],{},"            block, buffer = buffer.split(\"\u003C\u003CNAME>>\", 1)\n",[151,575,576],{"class":153,"line":266},[151,577,578],{},"            if block.strip():\n",[151,580,581],{"class":153,"line":272},[151,582,583],{},"                yield parse_name_block(block)\n",[151,585,586],{"class":153,"line":278},[151,587,164],{"emptyLinePlaceholder":163},[151,589,590],{"class":153,"line":284},[151,591,592],{},"    # 最后一个块没有后续\u003C\u003CNAME>>标记，单独处理\n",[151,594,595],{"class":153,"line":289},[151,596,597],{},"    if buffer.strip():\n",[151,599,600],{"class":153,"line":295},[151,601,602],{},"        yield parse_name_block(buffer)\n",[151,604,605],{"class":153,"line":301},[151,606,164],{"emptyLinePlaceholder":163},[151,608,609],{"class":153,"line":307},[151,610,164],{"emptyLinePlaceholder":163},[151,612,613],{"class":153,"line":312},[151,614,615],{},"def parse_name_block(text):\n",[151,617,618],{"class":153,"line":318},[151,619,620],{},"    \"\"\"从名字块中提取结构化数据\"\"\"\n",[151,622,623],{"class":153,"line":324},[151,624,625],{},"    result = {}\n",[151,627,629],{"class":153,"line":628},20,[151,630,631],{},"    for line in text.strip().split(\"\\n\"):\n",[151,633,635],{"class":153,"line":634},21,[151,636,637],{},"        if \"：\" in line:\n",[151,639,641],{"class":153,"line":640},22,[151,642,643],{},"            key, value = line.split(\"：\", 1)\n",[151,645,647],{"class":153,"line":646},23,[151,648,649],{},"            result[key.strip()] = value.strip()\n",[151,651,653],{"class":153,"line":652},24,[151,654,655],{},"    return result\n",[13,657,658],{},"前端通过 SSE（Server-Sent Events）接收，每收到一个完整的名字块就立即渲染，用户看到的效果是名字一个接一个地\"跳出来\"——比等 10 秒后一次性展示 5 个名字的体验好得多。",[13,660,661],{},"SSE 在 Nginx 后面有个经典坑：Nginx 默认会 buffer 响应，导致前端收不到实时推送。需要两处配置：",[40,663,667],{"className":664,"code":665,"language":666,"meta":49,"style":49},"language-nginx shiki shiki-themes github-dark github-light","# nginx.conf\nlocation \u002Fapi\u002F {\n    proxy_buffering off;                    # 关闭proxy层buffering\n    proxy_set_header X-Accel-Buffering no;  # 关闭X-Accel层buffering\n    proxy_pass http:\u002F\u002Fbackend;\n}\n","nginx",[47,668,669,675,689,704,715,723],{"__ignoreMap":49},[151,670,671],{"class":153,"line":154},[151,672,674],{"class":673},"si27w","# nginx.conf\n",[151,676,677,681,685],{"class":153,"line":160},[151,678,680],{"class":679},"spKkM","location",[151,682,684],{"class":683},"sqoU-"," \u002Fapi\u002F ",[151,686,688],{"class":687},"shWlK","{\n",[151,690,691,694,698,701],{"class":153,"line":167},[151,692,693],{"class":679},"    proxy_buffering ",[151,695,697],{"class":696},"sTU5a","off",[151,699,700],{"class":687},";                    ",[151,702,703],{"class":673},"# 关闭proxy层buffering\n",[151,705,706,709,712],{"class":153,"line":173},[151,707,708],{"class":679},"    proxy_set_header ",[151,710,711],{"class":687},"X-Accel-Buffering no;  ",[151,713,714],{"class":673},"# 关闭X-Accel层buffering\n",[151,716,717,720],{"class":153,"line":179},[151,718,719],{"class":679},"    proxy_pass ",[151,721,722],{"class":687},"http:\u002F\u002Fbackend;\n",[151,724,725],{"class":153,"line":185},[151,726,258],{"class":687},[13,728,729,730,733],{},"同时后端响应头也要加 ",[47,731,732],{},"X-Accel-Buffering: no","，双保险。",[32,735,737],{"id":736},"四六层质量过滤","四、六层质量过滤",[13,739,740],{},"LLM 生成的名字不能直接展示，需要经过多层质量把关。每一层解决一个具体问题：",[136,742,744],{"id":743},"第-1-层烂大街字黑名单","第 1 层：烂大街字黑名单",[40,746,748],{"className":145,"code":747,"language":147,"meta":49,"style":49},"BANNED_CHARS = set(\"梓涵轩诺萱妍泽宇欣怡浩瑞昊辰\")\n",[47,749,750],{"__ignoreMap":49},[151,751,752],{"class":153,"line":154},[151,753,747],{},[13,755,756],{},"为什么要过滤这些字？2023 年新生儿重名统计，\"梓涵\"连续多年霸榜。用了这些字，再好的诗词出处也白搭——别人一看就知道是 AI 起的\"模板名\"。宁可少生成，也不能出烂大街的字。",[136,758,760],{"id":759},"第-2-层谐音梗检测","第 2 层：谐音梗检测",[13,762,763],{},"姓+名组合的谐音问题，比如\"杨伟\"、\"范统\"、\"杜子腾\"。维护一个谐音黑名单，每个新名字都做组合检测。这类问题一旦漏掉，用户体验直接归零。",[136,765,767],{"id":766},"第-3-层生僻字过滤","第 3 层：生僻字过滤",[13,769,770],{},"拒绝 CJK 扩展区（0x9FFF 以上）的字。名字是用来叫的，别人叫不出来、打不出来，再有文化也白搭。",[40,772,774],{"className":145,"code":773,"language":147,"meta":49,"style":49},"def has_rare_char(name):\n    return any(ord(c) > 0x9FFF for c in name)\n",[47,775,776,781],{"__ignoreMap":49},[151,777,778],{"class":153,"line":154},[151,779,780],{},"def has_rare_char(name):\n",[151,782,783],{"class":153,"line":160},[151,784,785],{},"    return any(ord(c) > 0x9FFF for c in name)\n",[136,787,789],{"id":788},"第-4-层音韵评分","第 4 层：音韵评分",[13,791,792],{},"用 pypinyin 拆解声母韵母和声调，对名字做可读性评分。主要检测：",[794,795,796,803,809,815],"ul",{},[797,798,799,802],"li",{},[17,800,801],{},"同声母连读","：如\"赵兆\"，zh-zh 连读拗口",[797,804,805,808],{},[17,806,807],{},"同韵母连读","：如\"林音\"，in-in 听起来像一个字",[797,810,811,814],{},[17,812,813],{},"三声连读","：两个三声字连读需要变调，处理不好会奇怪",[797,816,817,820],{},[17,818,819],{},"整体韵律","：声调起伏太平或太陡都不好",[13,822,823],{},"评分低于 60 分的直接过滤。",[136,825,827],{"id":826},"第-5-层五格数理","第 5 层：五格数理",[13,829,830],{},"这是最\"不技术\"的一层，但对产品转化至关重要。",[13,832,833,834,837],{},"五格数理（天格、人格、地格、外格、总格）是中国传统取名的参考体系，用姓名笔画数对应 81 数理的吉凶。开发者可能觉得这是迷信，但准爸妈们",[17,835,836],{},"在乎","——他们会拿着你给的名字去\"起名网\"验证五格，如果人格是\"大凶\"，他们不会用你的产品。",[13,839,840],{},"所以系统用康熙字典笔画数自动计算五格，人格落\"大凶\"的组合直接排除。这层不是给开发者看的，是给用户信心的。",[40,842,844],{"className":145,"code":843,"language":147,"meta":49,"style":49},"def wuge_is_bad(surname, name):\n    \"\"\"检查五格数理是否为大凶\"\"\"\n    strokes = get_kangxi_strokes(surname + name)\n    ren_grid = strokes[0] + strokes[1]  # 人格 = 姓末字+名首字笔画\n    return ren_grid in BAD_NUMBERS  # 81数理中的大凶数\n",[47,845,846,851,856,861,866],{"__ignoreMap":49},[151,847,848],{"class":153,"line":154},[151,849,850],{},"def wuge_is_bad(surname, name):\n",[151,852,853],{"class":153,"line":160},[151,854,855],{},"    \"\"\"检查五格数理是否为大凶\"\"\"\n",[151,857,858],{"class":153,"line":167},[151,859,860],{},"    strokes = get_kangxi_strokes(surname + name)\n",[151,862,863],{"class":153,"line":173},[151,864,865],{},"    ren_grid = strokes[0] + strokes[1]  # 人格 = 姓末字+名首字笔画\n",[151,867,868],{"class":153,"line":179},[151,869,870],{},"    return ren_grid in BAD_NUMBERS  # 81数理中的大凶数\n",[136,872,874],{"id":873},"第-6-层历史去重","第 6 层：历史去重",[13,876,877],{},"用户点\"换一批\"时，新生成的名字不能和之前展示过的重复。session 中维护已展示名字集合，每层过滤后做最终去重。",[13,879,880],{},"六层全通过，才算一个合格的名字。实测下来，LLM 每轮生成 5 个名字，平均有 1-2 个会被过滤掉，所以系统会多生成几个作为缓冲。",[32,882,884],{"id":883},"五踩过的坑","五、踩过的坑",[136,886,888],{"id":887},"坑-1让-llm-不编造有多难","坑 1：让 LLM \"不编造\"有多难",[13,890,891],{},"最初 prompt 只写了\"请使用提供的诗句\"，编造率约 30%。加了\"绝不编造任何诗句或出处\"后降到 10%。加上后处理的精确匹配校验，才做到零编造。",[13,893,894,895,898],{},"经验：",[17,896,897],{},"prompt 约束是第一道防线，后处理校验是兜底","。两道都不能少。只靠 prompt 就像只靠自律——大部分时候有用，但总会翻车。",[136,900,902],{"id":901},"坑-2faiss-索引的冷启动","坑 2：FAISS 索引的冷启动",[13,904,905],{},"525MB 的索引文件，首次加载要几秒。改用 mmap 后 RSS 占用从几个 GB 降到几十 MB，但第一次查询仍然有冷启动延迟（需要把向量数据从磁盘读入页缓存）。",[13,907,908],{},"解决方案：服务启动时做一次空查询\"预热\"，把常用页拉入缓存。",[40,910,912],{"className":145,"code":911,"language":147,"meta":49,"style":49},"# 服务启动后预热FAISS索引\nwarmup_vec = np.zeros((1, dim), dtype=np.float32)\nindex.search(warmup_vec, k=1)  # 触发页缓存加载\n",[47,913,914,919,924],{"__ignoreMap":49},[151,915,916],{"class":153,"line":154},[151,917,918],{},"# 服务启动后预热FAISS索引\n",[151,920,921],{"class":153,"line":160},[151,922,923],{},"warmup_vec = np.zeros((1, dim), dtype=np.float32)\n",[151,925,926],{"class":153,"line":167},[151,927,928],{},"index.search(warmup_vec, k=1)  # 触发页缓存加载\n",[136,930,932],{"id":931},"坑-3embedding-查询缓存的必要性","坑 3：Embedding 查询缓存的必要性",[13,934,935],{},"相同输入（同姓氏+同性别+同风格）的查询会反复出现。为 query embedding 加了 LRU 缓存（maxsize=128），命中率出乎意料地高——同一个 session 内的\"换一批\"操作，只有方向词在变，基础 query 的 embedding 可以复用。",[32,937,939],{"id":938},"六实际效果","六、实际效果",[13,941,942,943,946,947,952],{},"以上技术方案已经落地为一个完整产品——",[17,944,945],{},"文间拾字","（",[948,949,951],"a",{"href":950},"\u002Fprojects\u002Fchinese-poetry-give-name","项目页","）。展示几张实际运行效果：",[13,954,955,958],{},[17,956,957],{},"输入界面","：用户填写姓氏、性别、出生时间，选择风格偏好：",[13,960,961],{},[962,963],"img",{"alt":964,"src":965},"古诗词AI取名工具的输入界面：姓氏、性别、风格偏好与偏好描述表单","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-rag\u002Fhome.png?imageMogr2\u002Fthumbnail\u002F1200x\u002Fformat\u002Fwebp\u002Fquality\u002F88",[13,967,968],{},[969,970,971],"em",{},"图 1：输入界面。表单式与对话式两种入口，风格偏好决定后续检索的意象方向。",[13,973,974,977],{},[17,975,976],{},"生成过程","：通过 SSE 流式推送，名字逐个\"跳出来\"，加载期间展示古诗词轮播：",[13,979,980],{},[962,981],{"alt":982,"src":983},"生成过程：加载期间轮播古诗词，已生成的名字卡片逐个出现","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-rag\u002Fgenerating.png?imageMogr2\u002Fthumbnail\u002F1200x\u002Fformat\u002Fwebp\u002Fquality\u002F88",[13,985,986],{},[969,987,988],{},"图 2：生成过程。加载期间轮播古诗词，进度条上方标出当前处在\"检索诗词\"还是\"组合名字\"阶段。",[13,990,991,994],{},[17,992,993],{},"结果展示","：每个名字附带完整信息——诗词出处（朝代+作者+原句）、五行标注、音韵分析、取名思路：",[13,996,997],{},[962,998],{"alt":999,"src":1000},"取名结果：每个名字附带诗词出处、寓意解析与音律标注","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-rag\u002Fresult.png?imageMogr2\u002Fthumbnail\u002F1200x\u002Fformat\u002Fwebp\u002Fquality\u002F88",[13,1002,1003],{},[969,1004,1005],{},"图 3：取名结果。每个名字都有朝代+作者+原句可查，下面跟着逐字释义与音律标注。",[13,1007,1008],{},"每个名字卡片的信息密度很高：诗词原文保证有据可查，五行标注让用户知道\"补了什么\"，音韵分析让用户知道\"念起来好不好听\"，取名思路让用户理解\"为什么选这两个字\"。",[32,1010,1012],{"id":1011},"七写在最后","七、写在最后",[13,1014,1015,1016,20],{},"这个系统的核心思路是：",[17,1017,1018],{},"用 RAG 架构约束 LLM 的幻觉，用向量检索保证诗词出处的真实性，用域知识（八字五行）增强检索的相关性，用多层过滤保证名字的质量",[13,1020,1021],{},"技术栈并不复杂——FAISS、Embedding、LLM、SQLite，都是成熟的工具。真正的难点在于把\"古诗词取名\"这个垂直领域的业务逻辑（五行、音韵、五格）和技术架构（向量检索、流式输出、质量过滤）有机地融合在一起。",[13,1023,1024],{},"如果你也在做 RAG 相关的项目，欢迎一起聊聊。特别是\"如何约束 LLM 不编造引用源\"这个问题，很想听听大家的方案。",[1026,1027],"hr",{},[136,1029,1030],{"id":1030},"体验一下",[13,1032,1033],{},"上面拆解的所有技术，都已经跑在这个产品里了：",[10,1035,1036,1042],{},[13,1037,1038,1041],{},[17,1039,1040],{},"微信搜索小程序「文间拾字」"," 即可体验。",[13,1043,1044],{},"收录《诗经》《楚辞》《全唐诗》《宋词》等经典，所有名字 100% 有诗词原文出处，零编造。",[13,1046,1047],{},"如果你身边有正在给宝宝起名的朋友，可以把这个工具分享给他们——比起花钱找大师，不如让 AI 翻遍 270 万句古诗词，给名字找一个真正有据可查的出处。",[13,1049,1050,1051,1054],{},"（文中代码节选自个人项目 ",[948,1052,1053],{"href":950},"chinese-poetry-give-name","，有删减；文中索引规模与模型配置以写稿时为准。）",[1056,1057,1058],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .si27w, html code.shiki .si27w{--shiki-default:#6A737D;--shiki-light:#6A737D}html pre.shiki code .spKkM, html code.shiki .spKkM{--shiki-default:#F97583;--shiki-light:#D73A49}html pre.shiki code .sqoU-, html code.shiki .sqoU-{--shiki-default:#B392F0;--shiki-light:#6F42C1}html pre.shiki code .shWlK, html code.shiki .shWlK{--shiki-default:#E1E4E8;--shiki-light:#24292E}html pre.shiki code .sTU5a, html code.shiki .sTU5a{--shiki-default:#79B8FF;--shiki-light:#005CC5}",{"title":49,"searchDepth":160,"depth":160,"links":1060},[1061,1062,1067,1072,1080,1085,1086],{"id":34,"depth":160,"text":35},{"id":133,"depth":160,"text":134,"children":1063},[1064,1065,1066],{"id":138,"depth":167,"text":139},{"id":199,"depth":167,"text":200},{"id":339,"depth":167,"text":340},{"id":415,"depth":160,"text":416,"children":1068},[1069,1070],{"id":419,"depth":167,"text":420},{"id":442,"depth":167,"text":1071},"3.2 \u003C> 流式解析",{"id":736,"depth":160,"text":737,"children":1073},[1074,1075,1076,1077,1078,1079],{"id":743,"depth":167,"text":744},{"id":759,"depth":167,"text":760},{"id":766,"depth":167,"text":767},{"id":788,"depth":167,"text":789},{"id":826,"depth":167,"text":827},{"id":873,"depth":167,"text":874},{"id":883,"depth":160,"text":884,"children":1081},[1082,1083,1084],{"id":887,"depth":167,"text":888},{"id":901,"depth":167,"text":902},{"id":931,"depth":167,"text":932},{"id":938,"depth":160,"text":939},{"id":1011,"depth":160,"text":1012,"children":1087},[1088],{"id":1030,"depth":167,"text":1030},"2026-10-15","md",null,{},"\u002Fposts\u002Fchinese-poetry-rag",{"title":5,"description":49},"chinese-poetry-rag","posts\u002Fchinese-poetry-rag","用 LLM 取名的最大问题不是\"不好听\"，而是它会编造出处。这套系统的做法是：让每个名字都必须命中真实可检索的古诗词原文——FAISS 向量检索、把八字五行注入检索 query、自定义分隔符做流式增量解析，最后六层质量过滤兜底。附让 LLM 不编造的两道防线。",[1099,1100,91],"AI 应用","RAG","MhOlrECPOtKT9rS8tphoYSkLsg82UXhKWJYuFjh9DvQ",[1103,1107,1111,1112,1116,1119,1122],{"title":1104,"slug":1105,"date":1106},"不引 Ghostscript：我用纯 Go 给 PDF 做了一场「压缩手术」","pure-go-pdf-compression","2026-10-24",{"title":1108,"slug":1109,"date":1110},"Wails v3 升级实战：桌面提醒客户端从 v2 升到 v3，踩了 10 个不报错的坑","wails-v3-upgrade","2026-10-23",{"title":5,"slug":1095,"date":1089},{"title":1113,"slug":1114,"date":1115},"一个人做 AI 产品，我踩过的 9 个真实的坑","ecom-detail-ai-part3-pitfalls","2026-10-14",{"title":1117,"slug":1118,"date":1115},"Wails v2 实战：用 Go + Vue3 做一个真正能用的 AI 桌面应用","ecom-detail-ai-part2-wails",{"title":1120,"slug":1121,"date":1115},"我用 Go 搭了一条 AI Agent 流水线：从 1 张商品图到一整套淘宝详情页","ecom-detail-ai-part1-architecture",{"title":1123,"slug":1124,"date":1125},"AI 时代，如何把一个需求真正落地成应用？——一条\"文档驱动 + 实测修订\"的实战路径","ai-requirement-landing","2026-10-13",{"id":1127,"title":1128,"architecture":1091,"body":1129,"category":1351,"client":1352,"cover":1353,"date":1354,"demo":1314,"demoMobile":1091,"description":49,"extension":1090,"featured":163,"features":1355,"github":1091,"manual":1372,"meta":1418,"modules":1091,"navigation":163,"order":190,"path":950,"seo":1419,"slug":1053,"stem":1420,"summary":1421,"techStack":1422,"visible":163,"year":1432,"__hash__":1433},"projects\u002Fprojects\u002Fchinese-poetry-give-name.md","古诗词AI取名工具",{"type":7,"value":1130,"toc":1343},[1131,1134,1137,1140,1143,1146,1148,1151,1183,1186,1189,1267,1270,1285,1288,1291,1306,1309,1318,1321,1327,1332,1338],[32,1132,1133],{"id":1133},"缘起",[13,1135,1136],{},"家里添了孩子，全家群里飘着几十个候选名，一半是短视频里抄的，一半是找人算的。我想自己从诗里翻一个，发现手头的电子文本根本搜不动：只有全文，没有按意象整理，人只能一句一句往下划。",[13,1138,1139],{},"那晚第一个脚本只做一件事——把「这个名字出自哪一句」和那句的意象对上。后来它长成了一个工具。",[32,1141,1142],{"id":1142},"背景",[13,1144,1145],{},"取名这件事的难处不在字数，在约束同时存在：要有出处，出处要读得通，读音不能和姓氏打架，字形别太生僻，家里长辈还往往另有一套五行上的要求。纯文学检索只管前一半，纯命理工具只管后一半，两边凑到一起时又容易变成随机拼字。要做的是把这两组约束放进同一次生成里，并且每个候选都能点开看到它来自哪首诗、哪一句。",[32,1147,476],{"id":476},[13,1149,1150],{},"名字的产出是一条流水线，从出生时辰走到候选项：",[794,1152,1153,1159,1165,1171,1177],{},[797,1154,1155,1158],{},[17,1156,1157],{},"命理分析","：按出生日期排八字四柱，算五行旺衰与喜用神，支持农历、公历双模式",[797,1160,1161,1164],{},[17,1162,1163],{},"两种方式找诗","：用户给的是「清雅一点」这种模糊偏好时，系统按意境去语料里找相近的诗句；给的是「名字里要有某个字」这种硬要求时，就逐字去原文里匹配。两路结果合并排序，既听得懂意境，也不漏掉指定字",[797,1166,1167,1170],{},[17,1168,1169],{},"来源均衡","：唐诗的数量远超其他朝代，直接按相关度取前几名会让候选几乎全是唐诗。系统按诗经、楚辞、唐诗、宋词分别给配额，保证来源不偏",[797,1172,1173,1176],{},[17,1174,1175],{},"取名生成","：把候选诗句、五行宜忌、生肖规则、姓氏的读音特点组装起来，交给大模型产出候选名",[797,1178,1179,1182],{},[17,1180,1181],{},"质量过滤","：五道关卡依次过——五格数理吉凶 → 禁用字与谐音 → 生僻字 → 读音是否顺口 → 五行是否相合，最后再综合排序",[13,1184,1185],{},"同一条流水线对外有三个入口：H5 网页、原生微信小程序、公众号关键词机器人。三者共用后端与配额体系——邀请码、微信登录、每日免费额度、关注公众号赠额度，都在同一处记账。",[32,1187,1188],{"id":1188},"技术架构",[54,1190,1191,1201],{},[57,1192,1193],{},[60,1194,1195,1198],{},[63,1196,1197],{},"模块",[63,1199,1200],{},"技术选型",[73,1202,1203,1211,1219,1227,1235,1243,1251,1259],{},[60,1204,1205,1208],{},[78,1206,1207],{},"后端",[78,1209,1210],{},"Python + FastAPI",[60,1212,1213,1216],{},[78,1214,1215],{},"前端",[78,1217,1218],{},"Vue3（H5）+ 原生微信小程序",[60,1220,1221,1224],{},[78,1222,1223],{},"运营后台",[78,1225,1226],{},"Go + Gin（另起进程，直接读同一批 SQLite 文件），管理端独立 Vue3 工程",[60,1228,1229,1232],{},[78,1230,1231],{},"检索",[78,1233,1234],{},"FAISS（IndexScalarQuantizer + 8-bit 量化，MMAP 按需加载）+ SQLite FTS5，RRF 加权融合",[60,1236,1237,1240],{},[78,1238,1239],{},"生成",[78,1241,1242],{},"智谱 Embedding-3（向量）+ DeepSeek-V4 Flash（LLM），SSE 流式输出",[60,1244,1245,1248],{},[78,1246,1247],{},"命理与字库",[78,1249,1250],{},"sxtwl 排八字、康熙字典笔画与字义、pypinyin 音律分析",[60,1252,1253,1256],{},[78,1254,1255],{},"数据",[78,1257,1258],{},"诗经、楚辞、全唐诗、宋词等古籍语料，约 38 万句",[60,1260,1261,1264],{},[78,1262,1263],{},"部署",[78,1265,1266],{},"Docker Compose + Nginx 反向代理",[13,1268,1269],{},"系统分七层：客户端（H5 \u002F 小程序）→ Nginx → FastAPI 应用层 → 中间件链 → 核心服务（八字、检索、生成、过滤排序）→ 数据存储（SQLite + FAISS）→ 外部模型服务。中间件链是五道：反爬签名、邀请码校验、IP 限流、免费额度、微信内容安全校验，规则改动不碰业务代码。",[13,1271,1272,1273,1276,1277,1280,1281,1284],{},"有三处工程细节值得单独说。一是",[17,1274,1275],{},"检索的双路融合","：纯语义检索擅长找\"意境相近\"但抓不住\"必须含某个字\"的硬约束，纯全文检索又读不懂\"清雅山河\"这样的抽象偏好，所以两路并行再用 RRF 加权合并，权重还能按场景调整。二是",[17,1278,1279],{},"排序权重","：音律 × 0.4 + 五格 × 0.3 + 出处 × 0.2 + 五行 × 0.1，四个维度可独立调节。三是",[17,1282,1283],{},"运营后台换了语言","：管理端的邀请码、命名规则、功能开关、统计与审计日志原先是 Python 后端的几个接口，后来抽成独立的 Go 服务——它不复制数据，直接读同一批 SQLite 文件，靠 WAL 模式保证跨语言读写安全。这样管理端的重启和 C 端请求互不影响。",[32,1286,1287],{"id":1287},"成果",[13,1289,1290],{},"一次取名请求就能拿到五组名字，每组都带着原句、作者、朝代、单字释义和音律说明；不满意可以换一批，不必重新描述一遍需求。「有出处」这件事是结构上保证的——名字只能从检索到的真实诗句里来，模型不负责编造引文。",[13,1292,1293,1294,1297,1298,1301,1302,1305],{},"上线以来累计生成已达",[17,1295,1296],{},"千次量级","，单次成本在",[17,1299,1300],{},"几分钱","，从点下按钮到看到候选名只需",[17,1303,1304],{},"几秒","——比找人起名或自己翻书都快，成本低到可以忽略。",[32,1307,1308],{"id":1308},"体验",[13,1310,1311,1312],{},"H5 版在线可用：",[948,1313,1317],{"href":1314,"rel":1315},"https:\u002F\u002Fname.bennywen.xyz\u002F",[1316],"nofollow","古诗词智能取名系统",[13,1319,1320],{},"微信小程序「文间拾字」：扫码或微信搜索体验，也可关注公众号获取取名灵感。",[13,1322,1323],{},[962,1324],{"alt":1325,"src":1326},"小程序码","https:\u002F\u002Fname.os.bennywen.xyz\u002Fmp-qrcode.jpg",[13,1328,1329],{},[969,1330,1331],{},"扫码体验小程序",[13,1333,1334],{},[962,1335],{"alt":1336,"src":1337},"公众号二维码","https:\u002F\u002Fname.os.bennywen.xyz\u002Fwechat-mp-qrcode.jpg",[13,1339,1340],{},[969,1341,1342],{},"关注公众号",{"title":49,"searchDepth":160,"depth":160,"links":1344},[1345,1346,1347,1348,1349,1350],{"id":1133,"depth":160,"text":1133},{"id":1142,"depth":160,"text":1142},{"id":476,"depth":160,"text":476},{"id":1188,"depth":160,"text":1188},{"id":1287,"depth":160,"text":1287},{"id":1308,"depth":160,"text":1308},"ai","商业项目","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-give-name\u002Fchinese-poetry-hero.webp","2026-06-22",[1356,1360,1364,1368],{"title":1357,"description":1358,"video":1359},"对话式输入","引导式问答或表单输入，描述取名偏好","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-give-name\u002Fchinese-poetry-demo.mp4",{"title":1361,"description":1362,"image":1363},"邀请码验证","邀请码系统控制访问权限，防止滥用","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-give-name\u002Fchinese-poetry-invite.webp",{"title":1365,"description":1366,"image":1367},"AI 取名生成","八字五行分析 + 诗词语义检索 + AI 生成","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-give-name\u002Fchinese-poetry-generating.webp",{"title":1369,"description":1370,"image":1371},"取名结果","诗词出处 + 单字释义 + 音律分析 + 五行匹配","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Fchinese-poetry-give-name\u002Fchinese-poetry-result.webp",{"specs":1373,"modules":1389,"deploy":1411,"limits":1415},[1374,1377,1380,1383,1386],{"label":1375,"value":1376},"交付形态","网页端 + 微信小程序 + 公众号三个入口，共用一套后端与配额",{"label":1378,"value":1379},"语料规模","诗经 \u002F 楚辞 \u002F 全唐诗 \u002F 宋词等古籍，约 38 万句",{"label":1381,"value":1382},"取名方式","八字五行 + 诗词检索 + AI 生成（DeepSeek），一次给 5 组候选名",{"label":1384,"value":1385},"出处保证","名字只能来自真实检索到的诗句，AI 不编造引文",{"label":1387,"value":1388},"准入方式","邀请码、微信登录、每日免费额度",[1390,1393,1395,1398,1401,1403,1406,1408],{"name":1391,"desc":1392},"取名主流程","填姓氏与出生信息，一次返回 5 组带出处的候选名",{"name":1157,"desc":1394},"排八字四柱、判五行旺衰、定喜用神，支持农历公历",{"name":1396,"desc":1397},"诗文检索","按意境找相近诗句，或按「名字里必须带某个字」定向",{"name":1399,"desc":1400},"文字鉴览","按参考文字查诗句原文与出处，查单字笔画、读音与字义",{"name":1181,"desc":1402},"五格、禁用字与谐音、生僻字、音律、五行五道关卡",{"name":1404,"desc":1405},"收藏与换一批","收藏心仪组合、一键复制、排除已展示名字重新生成",{"name":1223,"desc":1407},"邀请码、命名规则、功能开关、统计与审计日志",{"name":1409,"desc":1410},"公众号机器人","关键词规则自动回复，关注赠送体验额度",[1412,1413,1414],"一套编排即可启动全套服务（网页端、后端、运营后台），生产环境走宝塔面板","首次上线前需完成古籍语料预处理，约 30 分钟，支持断点续传","运营后台独立进程，可单独重启，不影响面向用户的服务",[1416,1417],"五行与五格是规则计算，不是命理判断；系统只保证每个名字有真实出处、读得通","需常驻上百 MB 的向量索引与字典数据，不适合部署在无状态的静态托管上",{},{"title":1128,"description":49},"projects\u002Fchinese-poetry-give-name","面向新手父母的古诗词取名工具——从 38 万句古籍语料里检索，每个名字都能翻到原句",[1423,1424,1425,1426,1427,1428,1429,1430,1431],"Python","FastAPI","Vue3","微信小程序","FAISS","SQLite FTS5","智谱 Embedding-3","DeepSeek","Go + Gin","2025","wGRoADq8aClqdo5vLMQ1_nyIRIyaGoD6HE-Iy99A9gU",1792857942075]