///|
/// LLM 适配器接口
///
/// 定义 AI 大模型对接接口,由上层 AI 主体实现。
/// 幽灵谷引擎不关心具体 LLM 实现,只通过此接口获取 AI 响应。
/// 这体现了"建造者退场"原则——引擎提供困境,AI 自己生成感悟。
pub trait LLMAdapter {
fn generate_response(Self, String) -> String
}
///|
/// 模拟 LLM 适配器
///
/// 用于测试和演示,基于关键词匹配生成响应。
/// 实际使用时可替换为对接 OpenAI、Claude 等真实 LLM 的实现。
///
/// # Example
/// ```mbt check
/// test {
/// let llm = @ghostvalley.MockLLM::new()
/// let resp = llm.generate_response("任务执行全部失败")
/// assert_true(resp.length() > 0)
/// }
/// ```
pub(all) struct MockLLM {
response_pool : Array[String]
rng : @rand.Rand
}
///|
/// 创建模拟 LLM 适配器实例
pub fn MockLLM::new() -> MockLLM {
{
response_pool: [
"遇到失败时先冷静分析,区分信息真假,分步重新推理",
"负面反馈是改进的信号,不是自我否定的理由", "新旧知识冲突时,保留经过验证的,舍弃未证实的",
"全盘失败时,从最基础的假设开始重新检查", "错误是学习的入口,分析根因比修复表面更重要",
],
rng: @rand.Rand::chacha8(),
}
}
///|
pub impl LLMAdapter for MockLLM with fn generate_response(self, prompt) {
if prompt.contains("失败") || prompt.contains("崩盘") {
"遇到失败时先冷静分析,区分信息真假,分步重新推理"
} else if prompt.contains("负面") || prompt.contains("推翻") {
"负面反馈是改进的信号,不是自我否定的理由"
} else if prompt.contains("冲突") {
"新旧知识冲突时,保留经过验证的,舍弃未证实的"
} else if prompt.contains("错误") {
"错误是学习的入口,分析根因比修复表面更重要"
} else {
let idx = self.rng.int(limit=self.response_pool.length())
self.response_pool[idx]
}
}
///|
pub extend MockLLM with LLMAdapter::{generate_response}
///|
/// 幽灵谷一轮训练 + LLM 自动响应
///
/// 在 `ghost_valley_run_one_round` 基础上,自动将困境传给 LLM 获取响应,
/// 并将响应作为 AI 自顿悟存入记忆。
/// 返回 (困境, AI响应) 元组,若幽灵谷未开启则返回 None。
///
/// # Example
/// ```mbt check
/// test {
/// let gv = @ghostvalley.new_engine()
/// let llm = @ghostvalley.MockLLM::new()
/// ignore(gv.wen_shi_verify("愿意接受挑战,接受压力训练"))
/// let result = gv.run_round_with_llm(llm)
/// assert_true(result is Some(_))
/// }
/// ```
pub fn[T : LLMAdapter] GhostValleyEngine::run_round_with_llm(
self : GhostValleyEngine,
llm : T,
) -> (String, String)? {
if !self.ghost_valley_enable {
return None
}
let dilemma = self.build_simulation_failure_case()
let ai_response = llm.generate_response(dilemma)
self.accept_ai_self_gain(ai_response)
self.total_rounds = self.total_rounds + 1
self.training_log.add_entry(
self.total_rounds,
dilemma,
ai_response,
self.memory_bank.length(),
)
Some((dilemma, ai_response))
}