Unity中使用LLMUnity遇到的问题(四)——大模型如何与应用程序进行互动(用人话控制你的应用程序)
大语言模型与人聊天那是行云流水般的自然,但如果是要大语言模型去Call别的系统,也就是让大语言模型与应用程序聊天,如何整呢?
·
- 问题来源:
大语言模型与人聊天那是行云流水般的自然,但如果是要大语言模型去Call别的系统,也就是让大语言模型与应用程序聊天,那就有点意思了!
比如说:金融量化接口向外公布了一系列API,你问大语言模型:请查询我的持仓?
大模型把这个操作需求,从【人话】转换成一系列的【API指令】,帮你发送查询命令,收到数据后,再把【查询结果】用【人话】反馈给你。
在Unity里面,你的虚拟仿真实验里,有一大堆实验步骤相关的信息和状态,当用户通过【AI助理】问:接下来的实验步骤是啥?
你可能会把【整个实验步骤信息表】喂给LLM,然后通过LLM自己去检索答案。
那么,万一用户说:请跳过当前步骤,执行后面的步骤。
此时此刻,你是不是应该反思,LLM是时候与应用程序进行交互了。

一、【和人聊天】 与 【与应用程序聊天】
-
盖棺定论:
- LLM 和人聊天 = 语言是目的
- LLM 和程序聊天 = 语言只是接口
-
LLM能听懂人话,那么它能把人话变成API指令吗?
- 使用可控输出:采用【Prompt提示词约束】,【Grammar 约束】、【GrammarJSON约束】
二、如何与应用程序聊天
- LLM能听懂人话,这是没问题的!
- 那么,如何用人话来跟你的应用程序进行交互呢?
- 你告诉LLM你要干啥,LLM把你的人话翻译成API指令,然后,你在把API指令转发给程序
- LLM如何把人话变成指令——使用输出约束
三、如何让LLM输出符合约束格式的指令信息
1、输出约束的种类
-
(1)总体来讲,包含【软约束】和【硬约束】。
- 【软约束】: 就是规劝约束,比如给LLMCharacter的面板指定它的prompt,或者每次聊天的时候,用文字提醒他要输出什么格式的内容。
- 【硬约束】就是强制约束,通过Grammar、GrammarJSON两个字段来约束,让模型按照规定的格式来输出。

-
(2)两种约束方式的异同(ChatGPT整理):
| 维度 | 软约束(Prompt) | 硬约束(Grammar / GrammarJSON) |
|---|---|---|
| 本质 | 给模型“建议”或“提示”如何输出 | 限制模型生成的 token / 输出结构 |
| 发生阶段 | 理解 / 推理阶段 | 解码 / 生成阶段 |
| 输出控制方式 | 模型自觉遵守 | 模型物理上无法违反 |
| 是否可被违反 | ✅ 可能 | ❌ 不可能 |
| 输出形式 | 自然语言 | 枚举值 / JSON 结构 |
| 可验证性 | ❌ 难以验证 | ✅ 天然可验证 |
| 工程稳定性 | 中 / 低 | 极高 |
| 抗干扰能力 | 弱(受上下文、温度、对抗输入影响大) | 强(无上下文污染、温度影响小) |
| 适合对象 | 人类阅读 / 教学 / 引导 | 程序消费 / API 调用 / 状态机 / Function Call |
| 典型角色 | ChatCharacter、RAGCharacter | IntentCharacter(Grammar)、ActionCharacter(GrammarJSON) |
| 作用 | 提供角色身份、语气、思维引导 | 保证输出格式正确、可解析、可直接驱动程序 |
| 是否保证语义正确 | ❌ 不保证 | ❌ 也不保证(只保证形式正确) |
| 常见误区 | 当做硬规则使用 | 不存在(生成器级别约束) |
2、LLMCharacter中与Grammar与GrammarJSON相关的几个变量有啥什么关联?
- (1)面板上的变量
- Grammar (string类型)
- GrammarJSON(string类型)

/// <summary> grammar file used for the LLMCharacter (.gbnf format) </summary>
[Tooltip("grammar file used for the LLMCharacter (.gbnf format)")]
[ModelAdvanced] public string grammar = null;
/// <summary> grammar file used for the LLMCharacter (.json format) </summary>
[Tooltip("grammar file used for the LLMCharacter (.json format)")]
[ModelAdvanced] public string grammarJSON = null;
- (2)代码里面的变量
- grammarString (string类型)
- grammarJSONString (string类型)
/// <summary> the grammar to use </summary>
[Tooltip("the grammar to use")]
public string grammarString;
/// <summary> the grammar to use </summary>
[Tooltip("the grammar to use")]
public string grammarJSONString;
- (3)逻辑关系溯源
在启动的时候,Awake()里面进行初始化和赋值
处理的过程:
通过面板配置参数,初始化真正的字段。
grammarString = Fn(Grammar)
grammarJSONString = Fn(GrammarJSON)
从给定的代码逻辑来看,面板参数配置的信息是路径,而是二选一的操作,具体操作如下:
protected virtual void InitGrammar()
{
grammarString = "";
grammarJSONString = "";
if (!String.IsNullOrEmpty(grammar))
{
grammarString = File.ReadAllText(LLMUnitySetup.GetAssetPath(grammar));
if (!String.IsNullOrEmpty(grammarJSON))
LLMUnitySetup.LogWarning("Both GBNF and JSON grammars are set, only the GBNF will be used");
}
else if (!String.IsNullOrEmpty(grammarJSON))
{
grammarJSONString = File.ReadAllText(LLMUnitySetup.GetAssetPath(grammarJSON));
}
}
2、Grammar和GrammarJSON使用场景
用户提出的问题,合并成以下几类:
- (1)GPT普通聊天:与LLM聊天
- (2)实验知识提问:基于RAG知识库的问题
- (3)实验过程交互:与程序进行交互操作
- A、查询实验状态:获取实验状态
- B、更改实验状态:更改实验状态

用户提问
↓
IntentCharacter (Grammar单项选择(意图分类器))
输出 intent → Chat / KnowledgeQA / QueryState / ModifyState
↓
分流
├─ Chat → 直接文本输出
├─ KnowledgeQA → RAG检索 → 文本输出
└─ QueryState / ModifyState → ActionCharacter (GrammarJSON)
输出 JSON 参数
↓
Unity 执行对应操作
↓
返回执行结果
↓
(可选)ActionCharacter生成用户可读说明
四、总结
如图~~
更多推荐


所有评论(0)