# 结果与诊断

四个求解入口都返回 `Solution`。先检查是否有可行解，再读取变量和派生表达式的值。

## 安全读取结果

```python
from optagent import OptModel

model = OptModel()
x = model.int(0, 10)
cost = 2 * x
model.constraint(x >= 3)
model.minimize(cost)
solution = model.solve(time_limit_s=1.0, log_level="off")

print(solution.status, solution.solver_name)
if solution.feasible:
    print(solution.objectives)
    print(x.value, cost.value)
else:
    print(solution.diagnostics)
```

| 字段 | 如何使用 |
| --- | --- |
| `feasible` | 是否取得可行赋值；不能用 `False` 单独判断无解 |
| `objectives` | 按模型声明顺序排列的目标值元组 |
| `status` | 终止状态；不同路径的字符串与大小写可能不同 |
| `solver_name` | 当前包装层标识：`search`、`highs`、`cpsat`、`mathopt` |
| `diagnostics` | 路径相关的诊断字典；用 `.get()` 读取可选字段 |

## 无值、超时与取消

未求解或模型变更后读取 `.value` 会抛出 `RuntimeError`。重新求解会清除旧值，因此应在变更或下一次求解前，将所需数值复制到业务数据结构。

本地搜索可能在序列化预算耗尽时返回 `deadline`，外部评价取消时返回 `cancelled`。CP-SAT / MathOpt 在验证前预算耗尽时返回 `UNKNOWN` 且无值。不要把这些状态视为不可行证明。

## 定位耗时阶段

| 路径 | 诊断字段 | 单位 / 含义 |
| --- | --- | --- |
| 本地搜索 | `python_serialize_ns` | Python 序列化纳秒数 |
| 本地搜索 | `python_wire_bytes` | 序列化载荷字节数 |
| 本地搜索 | `python_expression_count` | 表达式数量 |
| CP-SAT / MathOpt | `exact_phase_ms` | 各阶段耗时字典，单位毫秒 |
| CP-SAT / MathOpt | `exact_total_ms` | 包装层总耗时，单位毫秒 |
| CP-SAT / MathOpt 超时 | `termination_phase` | 预算终止阶段说明 |

诊断字段取决于执行到达的阶段。业务控制流优先依赖 `feasible` 和公开结果字段，不要要求每次返回都带有相同的内部统计。

## 常见问题

**模型可以创建，为什么求解器拒绝它？** 统一建模层比单个后端的表达能力更广。检查[路径兼容性](solvers.md)，尤其是非线性表达式、有限域边界和展开规模。

**为什么增加一条表达式后旧值不可读？** 新表达式改变模型，旧解被失效。先完成全部建模，再求解和读值。

**为什么设置一秒预算后调用稍晚才返回？** 预算采用协作式取消，正在执行的操作和结果清理会增加延迟。

**找不到内核或 OR-Tools？** 检查安装所用解释器与运行解释器一致，并按[安装说明](../start/installation.md)安装匹配的包和 extra。
