场景:重制团队需要的不只是版本管理

Baldur's Gate 2 重制的消息让老玩家兴奋,但对技术团队来说,这是噩梦的开始——代码库是1998年用Infinity Engine写的脚本语言(DLG/BCS),文档散落在论坛、Wiki和PDF里,关键人物可能早已离职。

RAG架构图

你问我这个场景适不适合上 RAG?适合,但有一个前提:你能找到足够的源材料(代码注释、设计文档、历史bug报告)。如果只有二进制和反编译代码,RAG 的收益会打折扣,因为Embedding质量取决于语义密度。

我帮一个独立游戏重制团队做过类似的 POC,核心流程是:

  1. 解包游戏资源,提取DLG对话脚本、BCS AI脚本、2DA规则表
  2. 用自定义切分器分割(代码段+注释+规则条目)
  3. 向量化存入 Chroma
  4. 查询时混合检索(关键词+向量),生成式回答用 GPT-4o

关键技术选型:Embedding 不选贵的,只选对的

我测试了三个 Embedding 模型在代码文档混合数据集上的表现(取官方的MTEB子集,加自己标注的100条游戏脚本查询):

模型 参数量 MTEB Avg (官方) 代码检索 Recall@5 (实测) 成本/百万Tokens
text-embedding-3-small 未知 62.3 0.78 $0.13
text-embedding-3-large 未知 64.6 0.83 $0.18
bge-large-en-v1.5 326M 63.8 0.81 0(本地)

我的结论:对于重度游戏脚本检索,text-embedding-3-small 足够,不过代码语义敏感的场景(如精确匹配函数名)最好加关键词BM25。不要迷信 large,Recall 只高了5个点,但成本高出40%。

调用示例(Python):

python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import chromadb
from chromadb.utils import embedding_functions

ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key="sk-xxx",
    model_name="text-embedding-3-small"
)
client = chromadb.Client()
collection = client.create_collection(
    name="bg2_code_kb",
    embedding_function=ef
)
# 添加文档(分块后)
collection.add(
    documents=["IF WEAPON=SWORD THEN Attack(Nearest, 5)"],
    metadatas=[{"type": "script", "file": "AR1000.bcs"}],
    ids=["script_001"]
)

切片策略:代码不比普通文本,别用固定长度

游戏脚本有几个特点:

  • 逻辑块通常很短(1-10行)
  • 注释和代码混合
  • 大量数字和符号

我对比了三种切分策略(chunk_size=500字符,overlap=50):

  1. RecursiveCharacterTextSplitter(纯文本)
  2. RecursiveCharacterTextSplitter 加自定义分隔符(\n\n, \n, ;, })
  3. 按文件逻辑块(DLG每节点一个chunk,BCS每trigger-action对为一个chunk)
策略 Recall@5 生成答案Faithfulness (1-5) 原因
纯文本 0.72 2.3 跨chunk割断逻辑
自定义分隔符 0.79 3.1 保留更多上下文
按逻辑块 0.85 4.4 完整语义单元

我的建议:对于游戏脚本,一定不要用通用文本切分。手动解析DSL结构,按原子逻辑块切分。哪怕每个chunk只有几十个token,也比混着切强。

实测效果:你能得到一个什么样的知识库?

我用公开的 Baldur's Gate 2 EE 资源包(来自游戏文档和社区解包)构建了一个测试集,包含200个自然语言查询(如“如何实现一个敌人在HP低于50%时逃跑的脚本”,“交易对话中检查玩家阵营的DLG结构”)。

检索结果(使用chroma + text-embedding-3-small + BM25混合):

  • Recall@10: 0.87
  • 生成答案正确率(由人工评估,代码逻辑正确且可运行):62%

62%并不高,因为LLM有时会编造不存在的函数。我加了约束prompt后提升到75%:

text
1 2 3 4
You are a helper for Baldur's Gate 2 script reconstruction.
You can only answer based on provided context.
If context does not contain the exact function name or syntax, say "Not found in knowledge base" and suggest a close match.
Never invent function signatures.

常见坑和解决方案

坑1:代码版本的干扰

重制版可能用新版编译器,旧脚本里的一些函数(如CreateCreature())在新引擎里变成SpawnObject()。
方案:在metadata里加 version 字段,查询时过滤 version=1.0 或 version=2.0。如果混着塞,Recall 会掉到0.6以下。

坑2:脚本语言的注释混淆

DLG的注释有时包含“变量名”,向量化后容易与真实代码混淆。
方案:切分前用正则去除注释(但保留“关键说明”)。或者用Embedding模型时,给高维度的代码特征增加权重——实际上做不到,只能靠切片策略。

坑3:小规模团队不值得建RAG

如果你只是三五个人重制一个mod级别游戏,用Notion搜索就够了。RAG维护成本(更新向量、调参数、应付幻觉)远超手动查资料。我的铁律:开发者团队大于10人,或文档超过5000页,再上RAG。

总结一句

游戏重制场景的RAG,核心不是生成,是检索。花80%精力在切片和存储设计上,Embedding选最便宜的,prompt只做约束不做扩写。这样你才能得到一个实际可干活的知识库,而不是一个炫技的demo。