Godot LLM
在游戏中使用大型语言模型(LLM)生成内容是不是很酷?LLM在NPC模型、游戏机制和设计辅助方面有巨大潜力。得益于llama.cpp等技术,"小型"LLM(如llama-3-8B)可以在没有高性能GPU的低端机器上合理运行。我想在Godot中实验LLM,但找不到好用的库,所以决定在这里创建一个。
⚠ 虽然LLM争议比图像生成模型少,但在游戏中集成LLM内容仍可能存在法律问题。我创建了另一个页面来记录一些相关信息。
目录
快速入门
安装
- 直接从资源库获取
Godot LLM
,或从发布页面下载vulkan或cpu版本的zip文件,解压后放入Godot项目的addons
文件夹 - 现在你应该能在Godot编辑器中看到
GdLlama
、GdEmbedding
、GDLlava
和LlmDB
节点。你可以将它们添加到Godot编辑器中的场景,或直接用.new()
初始化它们。
文本生成:GDLlama节点
- 下载GGUF格式的支持LLM模型(推荐:Meta-Llama-3-8B-Instruct-Q5_K_M.gguf),将文件移动到Godot项目中的某个位置
- 用GDScript设置模型,将
model_path
指向你的GGUF文件。默认的n_predict = -1
会生成无限序列,这里我们希望它短一些
func _ready():
var gdllama = GDLlama.new()
gdllama.model_path = "./models/Meta-Llama-3-8B-Instruct.Q5_K_M.gguf" ##你的模型路径
gdllama.n_predict = 20
- 从"Hello"开始生成文本
var generated_text = gdllama.generate_text_simple("Hello")
print(generated_text)
- 文本生成较慢,你可能想调用
gdllama.run_generate_text("Hello", "", "")
在后台运行生成,然后处理generate_text_updated
或generate_text_finished
信号
gdllama.generate_text_updated.connect(_on_gdllama_updated)
gdllama.run_generate_text("Hello", "", "")
func _on_gdllama_updated(new_text: String):
print(new_text)
文本嵌入:GDEmbedding节点
- 下载GGUF格式的支持嵌入模型(推荐:mxbai-embed-large-v1.Q5_K_M.gguf),将文件移动到Godot项目中的某个位置
- 用GDScript设置模型,将
model_path
指向你的GGUF文件
func _ready():
var gdembedding= GDEmbedding.new()
gdembedding.model_path = "./models/mxbai-embed-large-v1.Q5_K_M.gguf"
- 计算"Hello world"的嵌入向量,以PackedFloat32Array形式返回
var array: PackedFloat32Array = gdembedding.compute_embedding("Hello world")
print(array)
- 计算"Hello"和"World"之间的相似度
var similarity: float = gdembedding.similarity_cos_string("Hello", "World")
print(similarity)
- 嵌入计算可能较慢,你可能想调用
gdembedding.run_compute_embedding("Hello world")
或gdembedding.run_similarity_cos_string("Hello", "Worlld")
在后台运行计算,然后处理compute_embedding_finished
和similarity_cos_string_finished
信号
gdembedding.compute_embedding_finished.connect(_on_embedding_finished)
gdembedding.run_compute_embedding("Hello world")
func _on_embedding_finished(embedding: PackedFloat32Array):
print(embedding)
gdembedding.similarity_cos_string_finished.connect(_on_embedding_finished)
gdembedding.run_similarity_cos_string("Hello", "Worlld")
func _on_similarity_finished(similarity: float):
print(similarity)
注意,当前实现每个节点只允许一个线程运行,避免连续调用两个run_*
方法:
## 不要这样做,这会使你的UI卡住
gdembedding.run_compute_embedding("Hello world")
gdembedding.run_similarity_cos_string("Hello", "Worlld")
相反,在调用run_*
函数之前,总是等待finished信号或检查gdembedding.is_running()
。
多模态文本生成:GDLlava 节点
- 下载一个支持的多模态模型的 GGUF 格式文件(推荐:llava-phi-3-mini-int4.gguf),注意需要两个文件 - 一个
gguf
语言模型和一个 mmproj 模型(通常名为*mmproj*.gguf
),将文件移至 Godot 项目中的某个位置 - 使用 GDScript 设置模型,将
model_path
和mmproj_path
指向对应的 GGUF 文件
func _ready():
var gdllava = GDLlava.new()
gdllava.model_path = "./models/llava-phi-3-mini-int4.gguf"
gdllava.mmproj_path = "./models/llava-phi-3-mini-mmproj-f16.gguf"
- 加载图像(
svg
、png
或jpg
,只要 Godot 支持的其他格式也可以),或使用游戏画面(viewport)作为图像
var image = Image.new()
image.load("icon.svg")
## 或者加载游戏画面
#var image = get_viewport().get_texture().get_image()
- 生成文本以"提供完整描述"该图像
var generated_text = gdllava.generate_text_image("提供完整描述", image)
print(generated_text)
- 文本生成较慢,可以调用
gdllama.run_generate_text("Hello", "", "")
在后台运行生成,然后处理generate_text_updated
或generate_text_finished
信号
gdllava.generate_text_updated.connect(_on_gdllava_updated)
gdllava.run_generate_text_image("提供完整描述", image)
func _on_gdllava_updated(new_text: String):
print(new_text)
向量数据库:LlmDB 节点
- LlmDB 节点扩展自 GDEmbedding 节点,按照上一节下载模型并设置
model_path
func _ready():
var db = LlmDB.new()
db.model_path = "./models/mxbai-embed-large-v1.Q5_K_M.gguf"
- 打开数据库,默认创建并连接到
llm.db
文件
db.open_db()
- 设置文本数据元数据的结构,第一个元数据应始终是
id
字段,数据类型为String
,这里我们使用LlmDBMetaData.create_text
、LlmDBMetaData.create_int
和LlmDBMetaData.create_real
函数定义元数据的结构及相应的数据类型。
db.meta = [
LlmDBMetaData.create_text("id"),
LlmDBMetaData.create_int("year"),
LlmDBMetaData.create_real("attack")
]
- 不同模型创建的嵌入向量大小不同,在创建表之前校准
embedding_size
属性
db.calibrate_embedding_size()
- 根据元数据创建表,默认创建以下表:
llm_table_meta
:存储特定 id 的元数据llm_table
:存储带元数据和嵌入的文本- 一些名称包含
llm_table_virtual
的表:用于嵌入相似度计算的表
注意,在进行任何存储或检索操作之前,您的 .meta
属性应始终与数据库中的元数据列匹配,考虑在 _ready()
函数中或在检查器中设置 .meta
属性。
db.create_llm_tables()
- 存储一段带有指定
year
元数据的文本,如果某些元数据与文本无关,可以省略。如果输入文本长度超过chunk_size
,该函数会自动将其分割成较小的片段以适应chunk_size
。
var text = "Godot 由 Godot 基金会提供财务支持,这是一个非营利组织,于 2022 年 8 月 23 日通过荷兰 KVK(编号 87351919)成立。Godot 基金会负责管理对 Godot 的捐赠,并确保这些捐赠用于增强 Godot。Godot 基金会是一个独立的法律组织,不拥有 Godot。过去,Godot 作为软件自由保护协会的成员项目存在。"
db.store_text_by_meta({"year": 2024}, text)
- 检索 3 个与
godot
最相似且年份为 2024 的文本块:
print(db.retrieve_similar_texts("godot", "year=2024", 3))
- 根据嵌入模型,存储和检索可能较慢,考虑使用
run_store_text_by_meta
函数、run_retrieve_similar_texts
函数和retrieve_similar_text_finished
信号在后台存储和检索文本。此外,在不再使用数据库时调用close_db()
。
模板/演示
godot-llm-template 提供了一个相当完整的演示,展示了该插件的不同功能
检索增强生成(RAG)
该插件现在具备了简单检索增强生成(RAG)的所有基本组件。您可以将游戏世界或角色的信息存储到向量数据库中,检索相关文本以丰富提示,然后为游戏生成文本,生成的文本可以存回向量数据库以丰富未来的提示。RAG 弥补了 LLM 的不足 - 有限的上下文大小迫使模型忘记早期信息,而通过 RAG,信息可以存储在数据库中成为长期记忆,只检索相关信息来丰富提示,保持提示在上下文大小范围内。
开始时,您可以尝试以下格式作为提示输入:
文档:
{检索到的文本}
问题:
{您的提示}
路线图
功能
- 平台(后端):Windows(CPU、Vulkan)、macOS(CPU、Metal)、Linux(CPU、Vulkan)、Android(CPU)
- macOS 支持基于最大努力原则,因为我没有 Mac
- 基于 llama.cpp 的功能
- 文本生成
- 嵌入
- 多模态
- 基于 sqlite 和 sqlite-vec 的向量数据库集成
- 将文本分割成块
- 存储文本嵌入
- 将元数据与文本关联
- 通过嵌入相似度和元数据的 SQL 约束检索文本
待办事项
- iOS:构建应该很简单,但需要苹果开发者ID来运行构建
- 添加编辑器内文档,等待Godot 4.3的适当支持
- 添加实用函数生成有用的提示,如llama guard 2
- 直接从huggingface下载模型
- 自动从GDScript中的数据类生成JSON模式
- 更多llama.cpp功能
- 集成mlc-llm
- 有什么建议吗?
文档
检查器属性:GDLlama、GDEmbedding和GDLlava
此插件添加了3个基本节点:GdLlama
、GdEmbedding
和GdLlava
。
每种类型的节点都有一组影响计算性能和生成输出的属性。一些属性属于多个节点,它们对所有类型的节点通常具有相似的含义。
Model Path
:GGUF模型的位置Mmproj Path
:mmproj
GGUF文件的位置,仅适用于GdLlava
Instruct
:问答式交互模式Interactive
:自定义交互模式,你应该设置reverse_prompt
、input_prefix
和input_suffix
以建立流畅的交互Reverse Prompt
:AI在生成此提示后停止等待用户输入,一个好例子是"User:"Input Prefix
:在每个用户输入前附加Input Suffix
:在每个用户输入后附加Should Output prompt
:输出中是否应包括输入提示Should Output Special
:输出中是否应包括特殊标记(如序列开始和结束标记)Context Size
:模型一次可以处理的标记数N Predict
:生成新标记的数量,如果为-1则生成无限序列N Keep
:当模型用完context size
时,它开始忘记较早的上下文,设置此变量可强制模型保留最早的一些标记以保持对话相关性Temperature
:温度越高,生成的文本越随机Penalty Repeat
:惩罚重复序列,如果为-1则禁用Penalty Last N
:惩罚重复序列时考虑的最新标记数,如果为0则禁用,如果为-1则为Context Size
Penalize Nl
:惩罚换行符标记Top K
:仅从概率最高的这些标记中采样,如果为0则禁用Top P
:仅从累积概率内的标记中采样,如果为1.0则禁用Min P
:仅从至少具有此概率的标记中采样,如果为0.0则禁用N Thread
:使用的CPU线程数N GPU Layer
:卸载到GPU的层数Main GPU
:主要计算GPUSplit Mode
:如果系统中有多个GPU,计算将如何分配(0:无,1:层,2:行)Escape
:处理输入提示中的转义字符N Batch
:连续批处理期间每次迭代的最大标记数N Ubatch
:计算的最大批量大小
GdLlama函数和信号
函数
generate_text_simple(prompt: String) -> String
:从提示生成文本generate_text_json(prompt: String, json: String) -> String
:生成由JSON模式强制格式化的文本,参见以下部分generate_text_grammar(prompt: String, grammar: String) -> String
:生成由GBNF语法强制格式化的文本generate_text(prompt: String, grammar: String, json: String) -> String
:包装函数,如果grammar
非空则运行generate_text_grammar
,如果json
非空则运行generate_text_json
,否则运行generate_text_simple
run_generate_text(prompt: String, grammar: String, json: String) -> Error
:在后台运行generate_text
,依靠信号接收生成的文本,注意每个GDLlama节点只允许一个后台线程,当后台线程仍在运行时调用此函数将冻结逻辑,直到后台线程完成input_text(input: String)
:输入文本以与模型交互生成文本(启用Instruct
或Interactive
),仅在模型等待输入时有效,输入空字符串表示模型应继续生成之前的内容stop_generate_text()
:停止文本生成,清理模型和后台线程is_running() -> bool
:后台线程是否正在运行is_waiting_input() -> bool
:模型是否正在等待输入文本(启用Instruct
或Interactive
)
信号
generate_text_finished(text: String)
:文本生成完成时发出,包含完整生成的文本。启用Instruct
或Interactive
时,此信号在整个交互结束后发出generate_text_updated(new_text: String)
:无需等待完整生成的文本,每当生成新标记(文本序列的一部分)时就发出此信号,形成字符串流input_wait_started()
:模型现在开始等待用户输入,在启用Instruct
或Interactive
时发生,模型在对话中间停止生成文本以等待用户进一步输入
GDEmbedding函数和信号
函数
compute_embedding(prompt: String) -> PackedFloat32Array
:计算提示的嵌入向量similarity_cos_array(array1: PackedFloat32Array, array2: PackedFloat32Array) -> float
:计算两个嵌入向量之间的余弦相似度,这是一个快速函数,不加载模型similarity_cos_string(s1: String, s2: String) -> float
:计算两个字符串之间的余弦相似度run_compute_embedding(prompt: String) -> Error
:在后台运行compute_embedding(prompt: String)
,依靠compute_embedding_finished
信号接收嵌入向量,注意每个GDEmbedding节点只允许一个后台线程,当后台线程仍在运行时调用此函数将冻结逻辑,直到后台线程完成run_similarity_cos_string(s1: String, s2: String) -> Error
:在后台运行similarity_cos_string
,依靠compute_similarity_finished
信号接收余弦相似度,注意每个GDEmbedding节点只允许一个后台线程,当后台线程仍在运行时调用此函数将冻结逻辑,直到后台线程完成is_running() -> bool
:后台线程是否正在运行
信号
compute_embedding_finished(embedding: PackedFloat32Array)
:当run_compute_embedding
完成时触发similarity_cos_string_finished(similarity: float)
:当run_similarity_cos_string
完成时触发
GDLlava函数和信号
函数
generate_text_base64(prompt: String, image_base64: String) -> String
:根据提示和编码为jpg
或png
图像的base64字符串生成文本generate_text_image(prompt: String, image: Image) -> String
:根据提示和Godot中的Image
对象生成文本run_generate_text_base64(prompt: String, image_base64: String) -> Error
:在后台运行generate_text_base64
,依靠信号接收生成的文本,注意每个GDLlava节点只允许一个后台线程,当后台线程仍在运行时调用此函数将冻结逻辑,直到后台线程完成run_generate_text_base64(prompt: String, image: Image) -> Error
:在后台运行generate_text_base64
,依靠信号接收生成的文本,注意每个GDLlava节点只允许一个后台线程,当后台线程仍在运行时调用此函数将冻结逻辑,直到后台线程完成stop_generate_text()
:停止文本生成,清理模型和后台线程is_running() -> bool
:后台线程是否正在运行
信号
generate_text_finished(text: String)
:文本生成完成时触发,带有完整生成的文本generate_text_updated(new_text: String)
:不等待完整生成的文本,每当生成新的标记(文本序列的一部分)时触发此信号,形成字符串流
使用JSON模式生成文本
假设你想生成一个具有以下属性的角色:
name
:3到20个字符的字符串birthday
:特定日期格式的字符串weapon
:可选"sword"、"bow"或"wand"description
:至少10个字符的文本
首先创建一个GDLlama节点,通过检查器或脚本关闭Should Output prompt
和Should Output Special
:
should_output_prompt = false
should_output_special = false
在GDScript中构造以下_person_schema
字典:
var _person_schema = {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 3,
"maxLength": 20,
},
"birthday": {
"type": "string",
"format": "date"
},
"weapon": {
"enum": ["sword", "bow", "wand"],
},
"description": {
"type": "string",
"minLength": 10,
},
},
"required": ["name", "birthday", "weapon", "description"]
}
然后将其转换为JSON字符串:
var person_schema: String = JSON.stringify(_person_schema)
假设你对"魔法世界的主角"感兴趣,可以使用GDLlama
节点的generate_text_json(prompt, json_scheme)
生成角色:
var json_string: String = generate_text_json(prompt, json_scheme)
注意文本生成较慢,你可能想使用run_generate_text(prompt, "", json_scheme)
在后台运行生成,然后处理generate_text_finished
以接收生成的文本。
json_string
应该看起来像这样:
{"birthday": "2000-05-12", "description": "一位心地纯洁、带着顽皮微笑的年轻巫师。他拥有丰富的想象力和对冒险的热爱。他总是勇于接受挑战,不惧冒险。", "name": "艾瑞恩多·索恩", "weapon": "wand"}
现在,生成的数据已准备就绪,你可以将其解析回字典或其他对象以使用数据。
var dict: Dictionary = {}
var json = JSON.new()
var error = json.parse(json_string)
if (error == OK):
dict = json.data
print(dict["name"]) ##艾瑞恩多·索恩
检查器属性:LlmDB
LlmDB继承自GDEmbedding并共享其所有属性,请查看上面的相关信息。此外,LlmDB还有:
Meta
:LlmDBMetaData资源的数组,定义元数据的结构。LlmDBMetaData包含定义元数据名称的Data Name
和定义元数据数据类型的Data Type
(0=整数,1=实数,2=文本,3=二进制)。Meta
不应为空,且第一个元素应始终是数据类型为文本的id
。dB Dir
:数据库文件的目录,默认为项目的根目录dB File
:数据库文件的文件名,默认为llm.db
Table Name
:由create_llm_tables
函数创建的表的名称Embedding Size
:模型计算的嵌入向量大小,用于create_llm_tables
函数Absolute Separators
:字符串数组。存储文本时,文本首先会被这里定义的字符串分隔,如果分隔后的文本短于Chunk Size
或所有分隔符都已处理,分隔过程将停止。默认为\n
和\n\n
,在检查器中显示为空白。Chunk Separators
:字符串数组。在处理完Absolute Separators
后,这里的分隔符(第一个有效的)将被选择进一步分隔文本,然后将这些片段分组成块以满足Chunk Size
和Chunk Overlap
的要求Chunk Size
:任何文本块不应超过此大小,除非在遍历迭代器后分隔函数仍无法满足要求Chunk Overlap
:相邻文本块之间的最大重叠,算法将尝试在满足此约束的情况下创建最大可能的重叠
LlmDB函数和信号
除了GDEmbedding的函数和信号外,LlmDB还有一些额外的函数和信号
函数
calibrate_embedding_size()
:根据model_path
中的模型校准Embedding Size
为正确的数值open_db()
:如果文件不存在,则在dB_Dir
创建一个dB_File
,然后连接到数据库close_db()
:终止与数据库的连接execute(statement: String)
:执行一条SQL语句,在Project Settings
中打开Verbose stdout
可以查看该语句生成的日志create_llm_tables()
:如果表不存在,则创建一个名为Table Name
的表,一个Table Name
+_meta
表用于按id
存储预定义的元数据,以及一些_virtual
表drop_table(p_table_name: String)
:删除指定名称的表drop_llm_tables(p_table_name: String)
:删除由create_llm_tables()
创建的所有表(除了自动创建的用于自增的sqlite_sequence
表),即p_table_name
、p_table_name
+_meta
和所有名称包含p_table_name
+_virtual
的表has_table(p_table_name: String) -> bool
:检查是否存在该名称的表is_table_valid(p_table_name: String) -> bool
:检查表是否包含有效的元数据,即.meta
属性中的所有元素都存在于表中且数据类型正确store_meta(meta_dict: Dictionary)
:将一组元数据存储到Table Name
+_meta
表中,以id
作为主键,这样可以通过id调用store_text_by_id
,而不是通过store_text_by_meta
输入完整的元数据字典has_id(id: String, p_table_name: String) -> bool
:检查表中是否存储了特定idsplit_text(text: String) -> PackedStringArray
:首先按所有Absolute Separators
分割文本,然后按适当的Chunk Separators
之一分割,使任何文本块的长度都小于Chunk Size
(以字符计),且重叠部分接近但不大于Chunk Overlap
。如果算法无法满足这些约束,将打印错误消息,返回的块大小会大于Chunk Size
store_text_by_id(id: String, text: String)
:分割文本并将块存储在数据库中,注意应先调用store_meta
,确保具有相应元数据的id
已在数据库中run_store_text_by_id(id: String, text: String) -> Error
:在后台运行store_text_by_id
,完成时发出store_text_finished
信号store_text_by_meta(meta_dict: Dictionary, text: String)
:分割文本并将块与meta_dict
中定义的元数据一起存储在数据库中,注意元数据应有效,每个键应是存储在.meta
属性中的名称,且对应类型应正确run_store_text_by_meta(meta_dict: Dictionary, text: String) -> Error
:在后台运行store_text_by_meta
,完成时发出store_text_finished
信号retrieve_similar_texts(text: String, where: String, n_results: int) -> PackedStringArray
:检索与text
最相似的n_results
个文本块,where
应为空或一个SQL WHERE子句,用于按元数据过滤块run_retrieve_similar_texts(text: String, where: String, n_results: int) -> Error
:在后台运行retrieve_similar_texts
,完成时发出retrieve_similar_texts_finished
信号
信号
store_text_finished
:当run_store_text_by_id
或run_store_text_by_meta
完成时发出retrieve_similar_texts_finished(array: PackedStringArray)
:包含一个String
数组,当run_retrieve_similar_texts
完成时发出
LlmDBMetaData
这是一个简单的资源类,构成LlmDB中的meta
数组属性。它有两个属性:
data_name
:定义此元数据名称的String
data_type
:定义此元数据数据类型的int
(0=整数,1=实数,2=文本,3=二进制大对象),注意不建议在此输入整数,因为可能造成混淆,请使用检查器属性、LlmDBMetaData枚举或下面的函数LlmDBMetaDataType
枚举:LlmDBMetaData.INTEGER = 0
LlmDBMetaData.REAL = 1
LlmDBMetaData.TEXT = 2
LlmDBMetaData.BLOB = 3
有4个静态函数用于创建LlmDBMetaData:
create_int(data_name: String) -> LlmDBMetaData
:创建类型为int(0)的LlmDBMetaDatacreate_real(data_name: String) -> LlmDBMetaData
:创建类型为real(1)的LlmDBMetaDatacreate_text(data_name: String) -> LlmDBMetaData
:创建类型为text(2)的LlmDBMetaDatacreate_blob(data_name: String) -> LlmDBMetaData
:创建类型为blob(3)的LlmDBMetaData,注意blob数据类型支持仍在开发中
alternatively,您可以使用此静态函数创建LlmDBMetaData:
create(data_name: String, data_type: int) -> LlmDBMetaData
:通过data_name
和data_type
创建相应的LlmDBMetaData,建议对data_type
使用枚举而非int
常见问题
- 如何获取更多调试信息?
在Project Settings
中打开Verbose stdout
,考虑从终端运行Godot以获取额外的日志信息。
- 是否支持英语以外的语言?
是的,该插件使用utf8编码,因此天然支持多语言。但是,语言模型可能只用英语数据训练,无法生成英语以外的文本,请根据需求选择语言模型。
- 生成的文本中出现奇怪的标记,如在
Should Output Special
关闭时出现<eot_id>
。
欢迎随时提出问题。但请注意,GGUF格式的标准可能会改变以支持新特性和模型,因此bug可能来自模型而非插件。例如,某些旧版llama 3 GGUF模型可能与最新格式不兼容,你可以尝试搜索带有修复的新模型,如这个。
- 你正在运行Arch linux(或其衍生版如Manjaro),你的Godot编辑器崩溃。
Arch版本的Godot在使用GDExtension时存在bug,请从官方网站下载Godot。
- 你有独立显卡但看到"unable to load model"错误,你需确保正确设置了模型参数。 如果您为同一个GPU安装了多个驱动程序,目前Vulkan后端存在一个bug。请尝试将"Split Mode"设置为"NONE"(0),并手动设置您的"Main GPU"(从0开始)以查看是否能解决问题。
从源代码编译
为您的操作系统安装构建工具和Vulkan SDK,然后克隆此仓库
git clone https://github.com/Adriankhl/godot-llm.git
cd godot-llm
git submodule update --init --recursive
mkdir build
cd build
运行cmake
。
在Windows上:
cmake .. -GNinja -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DLLAMA_NATIVE=OFF -DLLAMA_VULKAN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCMAKE_BUILD_TYPE=Release
在Linux上:
cmake .. -GNinja -DLLAMA_NATIVE=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DLLAMA_VULKAN=ON -DCMAKE_BUILD_TYPE=Release
Vulkan构建适用于Windows和Linux。如果您想进行CPU构建,请将-DLLAMA_VULKAN=ON
改为-DLLAMA_VULKAN=OFF
。
对于Android,将$NDK_PATH
设置为您的Android NDK目录,然后:
cmake .. -GNinja -DCMAKE_TOOLCHAIN_FILE=$NDK_PATH\cmake\android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -DCMAKE_C_FLAGS="-mcpu=generic" -DCMAKE_CXX_FLAGS="-mcpu=generic" -DCMAKE_BUILD_TYPE=Release
您可能需要调整Android的编译标志以适应不同类型的CPU。
然后使用ninja
编译和安装:
ninja -j4
ninja install
../install/gpu/addons/godot_llm
文件夹(CPU构建则为cpu
而不是gpu
)可以直接复制到您的Godot项目的addons
文件夹中。
贡献
- 欢迎提交PR