---
title: "决定游戏角色的下一步动作"
description: "把角色状态变成 JSON，针对固定动作列表问一个单选问题，拿到选中的动作以及每个选项的概率。一次请求替代手写的 if-else 树。"
canonical: "https://system-one.dev/zh-CN/use-cases/npc-action"
language: "zh-CN"
---

# 决定游戏角色的下一步动作

**要点**

1. 游戏 AI 里大量是“从固定列表里挑一个动作”的决策，通常写成 if-else 树。
2. 一个 Choice 问题会返回选中的动作，以及每个选项背后的概率，游戏循环可以直接用这个结果，也能看第二名的概率有多接近。
3. 设计期规则留在你的代码里：动作列表、冷却时间以及任何硬约束都由你决定，不由模型决定。

## 为什么固定动作列表合适

角色的下一步是有界决策：攻击、喝药、逃跑、谈判、嘲讽。它不生成文本，所以游戏循环拿到的就是一个可以 switch 的字符串。

写成 if-else 意味着每个状态变量都要有人猜一个阈值。每个动作都有概率，可以让你看到这次选择有多果断——这对动画、难度调优，以及发现角色“犹豫”的状态都有用。

## 问题形状

```ts
import { choice } from '@system-one-ai/core';

export const actionQuestion = {
  next: choice('What should this character do next?', {
    attack: 'Close distance and attack the nearest enemy',
    potion: 'Drink a healing potion before acting',
    flee: 'Retreat toward the nearest exit',
    truce: 'Attempt to negotiate a pause',
    taunt: 'Provoke the enemies to draw them out',
  }),
};
```

把角色真实拥有的状态发过去：血量、敌人数量与最近距离、背包、地形，以及附近是否有同伴。

> 示意代码，未经过实际运行测试。阈值只是占位。

```ts
export async function nextAction(client, state: {
  healthPct: number; enemies: number; nearestEnemyM: number;
  potions: number; allyNearby: boolean; terrain: string;
}) {
  const result = await client.evaluate({ state, questions: actionQuestion });
  const pick = result.answers.next.choice;
  const confidence = result.answers.next.confidence;
  // 占位：模型不确定时交给脚本化行为
  return confidence >= 0.5 ? pick : 'hold_position';
}
```

## 哪些必须留在代码里

- **动作列表本身。** 选项是游戏设计，不是模型输出。
- **硬约束。** 冷却、沉默时不能喝药，以及规则引擎已经保证的东西，应该在调用之前就短路掉。
- **兜底行为。** 置信度低时，脚本化行为通常比掷硬币更好。

## 延迟与费用

本站示例展示的是示例数据，不是实时运行；如果要每帧调用，请先在自己的游戏里测延迟。典型的用法是一个回合一次决策，而不是一帧一次。

每 4KB 算一块，不足 4KB 也按一块。费用 = 块数 × 问题数 × 模型单价。一段角色状态通常一块就够。

新账号注册即送 100 积分，积分不会过期。详见 [定价](https://system-one.dev/zh-CN/pricing)。

[在线试用角色示例（需登录）](https://system-one.dev/zh-CN/demo/npc-action)，用示例数据看同一组问题。


## 常见问题

### 页面上的概率是实时算出来的吗？

不是。示例展示固定数据，切换模型也不会变。登录后可以跑自己的角色状态。

### 可以自定义动作吗？

可以。模型只在你列出的选项里选；选项上限见各模型页面。

### 能每帧调用吗？

不要这样假设。按每回合一次来设计，并先在自己的环境里测延迟。

### 冷却和规则该交给模型吗？

不该。硬约束留在规则引擎里，只把已经合法的状态发过去。
