remove rule ai
This commit is contained in:
@@ -1,19 +1,15 @@
|
||||
"""
|
||||
NPC AI的类。
|
||||
这里指的不是LLM或者Machine Learning,而是NPC的决策机制
|
||||
分为两类:规则AI和LLM AI
|
||||
NPC AI 的类。
|
||||
这里指的是 NPC 的决策机制。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
import random
|
||||
|
||||
from src.classes.world import World
|
||||
from src.classes.region import Region
|
||||
from src.classes.root import get_essence_types_for_root
|
||||
from src.classes.event import Event, NULL_EVENT
|
||||
from src.utils.llm import get_ai_prompt_and_call_llm_async
|
||||
from src.classes.typings import ACTION_NAME, ACTION_PARAMS, ACTION_PAIR, ACTION_NAME_PARAMS_PAIRS
|
||||
from src.classes.typings import ACTION_NAME_PARAMS_PAIRS
|
||||
from src.utils.config import CONFIG
|
||||
from src.classes.actions import ACTION_INFOS_STR
|
||||
|
||||
@@ -34,8 +30,8 @@ class AI(ABC):
|
||||
async def decide(self, world: World, avatars_to_decide: list[Avatar]) -> dict[Avatar, tuple[ACTION_NAME_PARAMS_PAIRS, str, str, Event]]:
|
||||
"""
|
||||
决定做什么,同时生成对应的事件。
|
||||
一个ai支持批量生成多个avatar的动作。
|
||||
这对LLM AI节省时间和token非常有意义。
|
||||
一个 AI 支持批量生成多个 avatar 的动作。
|
||||
这对 LLM AI 节省时间和 token 非常有意义。
|
||||
"""
|
||||
results = {}
|
||||
max_decide_num = CONFIG.ai.max_decide_num
|
||||
@@ -43,68 +39,12 @@ class AI(ABC):
|
||||
results.update(await self._decide(world, avatars_to_decide[i:i+max_decide_num]))
|
||||
|
||||
for avatar, result in list(results.items()):
|
||||
# 兼容:RuleAI 返回单动作,LLMAI 返回动作链
|
||||
if result and isinstance(result[0], list):
|
||||
action_name_params_pairs, avatar_thinking, objective = result # type: ignore
|
||||
else:
|
||||
action_name, action_params, avatar_thinking, objective = result # type: ignore
|
||||
action_name_params_pairs = [(action_name, action_params)]
|
||||
action_name_params_pairs, avatar_thinking, objective = result # type: ignore
|
||||
# 不在决策阶段生成开始事件,提交阶段统一触发
|
||||
results[avatar] = (action_name_params_pairs, avatar_thinking, objective, NULL_EVENT)
|
||||
|
||||
return results
|
||||
|
||||
class RuleAI(AI):
|
||||
"""
|
||||
规则AI(批量接口,内部逐个决策)
|
||||
"""
|
||||
|
||||
def __decide(self, world: World, avatar: "Avatar", regions: list[Region]) -> tuple[ACTION_NAME, ACTION_PARAMS, str, str]:
|
||||
"""
|
||||
单个 Avatar 的决策逻辑。
|
||||
先做一个简单的:
|
||||
1. 找到自己灵根对应的最好的区域
|
||||
2. 检测自己是否在最好的区域
|
||||
3. 如果不在,则移动到最好的区域
|
||||
4. 如果已经到达最好的区域,则进行修炼
|
||||
5. 如果需要突破境界了,则突破境界
|
||||
"""
|
||||
if random.random() < 0.1:
|
||||
return ("Play", {}, "", "放松一下,缓解修行压力")
|
||||
|
||||
best_region = self.get_best_region_for_avatar(avatar, regions)
|
||||
|
||||
if avatar.is_in_region(best_region):
|
||||
if avatar.cultivation_progress.can_break_through():
|
||||
return ("Breakthrough", {}, "", "尽快突破到更高境界")
|
||||
else:
|
||||
return ("Cultivate", {}, "", "稳步提升修为")
|
||||
else:
|
||||
return ("MoveToRegion", {"region": best_region.name}, "", f"前往{best_region.name}修行")
|
||||
|
||||
async def _decide(self, world: World, avatars_to_decide: list[Avatar]) -> dict[Avatar, tuple[ACTION_NAME, ACTION_PARAMS, str, str]]:
|
||||
"""
|
||||
决策逻辑:批量接口的实现上,逐个 Avatar 调用 __decide 进行独立决策,
|
||||
以保持规则AI的可控性与可测试性。
|
||||
"""
|
||||
results: dict[Avatar, tuple[ACTION_NAME, ACTION_PARAMS, str, str]] = {}
|
||||
regions: list[Region] = list(world.map.regions.values())
|
||||
|
||||
for avatar in avatars_to_decide:
|
||||
results[avatar] = self.__decide(world, avatar, regions)
|
||||
|
||||
return results
|
||||
|
||||
def get_best_region_for_avatar(self, avatar: "Avatar", regions: list[Region]) -> Region:
|
||||
"""
|
||||
根据avatar的灵根找到最适合的区域
|
||||
"""
|
||||
essence_types = get_essence_types_for_root(avatar.root)
|
||||
def best_density(region: Region) -> int:
|
||||
return max((region.essence.get_density(et) for et in essence_types), default=0)
|
||||
region_with_best_essence = max(regions, key=best_density)
|
||||
return region_with_best_essence
|
||||
|
||||
class LLMAI(AI):
|
||||
"""
|
||||
LLM AI
|
||||
@@ -154,5 +94,4 @@ class LLMAI(AI):
|
||||
results[avatar] = (pairs, avatar_thinking, objective)
|
||||
return results
|
||||
|
||||
llm_ai = LLMAI()
|
||||
rule_ai = RuleAI()
|
||||
llm_ai = LLMAI()
|
||||
@@ -7,7 +7,7 @@ from src.classes.age import Age
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.world import World
|
||||
from src.classes.event import Event, is_null_event
|
||||
from src.classes.ai import llm_ai, rule_ai
|
||||
from src.classes.ai import llm_ai
|
||||
from src.utils.names import get_random_name
|
||||
from src.utils.config import CONFIG
|
||||
from src.run.log import get_logger
|
||||
@@ -29,10 +29,7 @@ class Simulator:
|
||||
avatars_to_decide.append(avatar)
|
||||
if not avatars_to_decide:
|
||||
return
|
||||
if CONFIG.ai.mode == "llm":
|
||||
ai = llm_ai
|
||||
else:
|
||||
ai = rule_ai
|
||||
ai = llm_ai
|
||||
decide_results = await ai.decide(self.world, avatars_to_decide)
|
||||
for avatar, result in decide_results.items():
|
||||
action_name_params_pairs, avatar_thinking, objective, _event = result
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
llm:
|
||||
# 填入litellm支持的model name和key
|
||||
model_name: "your-model-name"
|
||||
fast_model_name: "your-fast-model-name"
|
||||
key: "your-api-key"
|
||||
base_url: "your-base-url-of-llm"
|
||||
key: "your-api-key" # 目前需要的是阿里的qwen api
|
||||
model_name: "openai/qwen-plus"
|
||||
fast_model_name: "openai/qwen-flash"
|
||||
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
max_parse_retries: 3
|
||||
|
||||
paths:
|
||||
@@ -11,7 +11,6 @@ paths:
|
||||
game_configs: static/game_configs/
|
||||
|
||||
ai:
|
||||
mode: "llm" # "rule" or "llm"
|
||||
max_decide_num: 4
|
||||
|
||||
game:
|
||||
|
||||
Reference in New Issue
Block a user