avada-eval
Safe, Decimal-exact expression evaluator for LLM tools, derived from simpleeval.
安全、可扩展、给大模型当计算工具用的表达式求值器。派生自
simpleeval(v1.0.8,commit
3b30888d0d5954df8a11b7e5ef26d17e19a96c29,MIT,© 2013-2026 Daniel Fairhead),
核心区别:用 decimal.Decimal 代替 float 做精确计算,并加固了资源耗尽(DoS)防护。
pip install avada-eval # 或 uv add avada-eval
需要 Python ≥ 3.11;唯一运行时依赖 beartype(运行时类型检查,AVADA_BEARTYPE_ON=false 可关闭)。
快速示例
from avada_eval import simple_eval, SimpleEval # 替换 `from simpleeval import ...`
simple_eval("0.1 + 0.2") # Decimal('0.3')
simple_eval("1 / 3") # Decimal('0.3333333333333333333333333333')
simple_eval("2 ** 100") # 1267650600228229401496703205376(int 精确)
simple_eval("price * qty", names={"price": 19.99, "qty": 3}) # Decimal('59.97')
Decimal 语义(与 simpleeval 的差异)
| 项 | simpleeval | avada-eval |
|---|---|---|
| 小数字面量 | float | 按源码原文构造的 Decimal(1.10 保留尾零) |
| 整数字面量 | int | int(** // % 位运算与 Python 一致) |
/ |
float | Decimal(int/int 亦然) |
负/小数指数 ** |
float | Decimal;Decimal 路径只限制指数,结果超出 Emax → NumberTooHigh |
Decimal 的 // % |
— | 取整向下(与 int/float 一致,而非 decimal 模块的截断) |
| 除零 | ZeroDivisionError |
DivisionByZero(同时是 InvalidExpression 与 ZeroDivisionError) |
| 外部 float | 原样 | float_policy="convert"(默认,Decimal(str(x)))或 "error"(FloatNotAllowed) |
| 默认函数 | rand randint int float str | 另加 decimal round abs min max sum;float()/rand() 返回 Decimal;sum 同 min/max 也接受直接传数(sum(1, 2, 3)) |
| 函数参数错误 | TypeError / ValueError |
InvalidArguments(个数/类型错)/ InvalidArgumentValue(值不可用),均为 InvalidExpression,且仍分别是 TypeError / ValueError;信息带表达式中的函数名与用法 |
| 精度/舍入 | — | context=decimal.Context(...),每次 eval 在 localcontext 中执行 |
默认 context:28 位有效数字、ROUND_HALF_EVEN、Emax/Emin = ±999999,InvalidOperation /
DivisionByZero / Overflow 以异常抛出。设计决策见
ADR 0002。
LLM 工具用法(avada_eval.llm)
from avada_eval.llm import evaluate_for_llm, TOOL_DESCRIPTION
evaluate_for_llm("revenue * 12.5% + 1,000", {"revenue": 80000}).to_dict()
# {'ok': True, 'normalized': 'revenue * 0.125 + 1000', 'value': '11000.000', 'variables': {'revenue': '80000'}, ...}
evaluate_for_llm从不因表达式错误而抛异常:语法错误、未知名字、除零、安全拒绝等都以ok=False+error/error_type返回,模型可据此重试;TOOL_DESCRIPTION可直接作为工具描述。 函数参数写错(pct_change(1)、round("x"))返回InvalidArguments等;库内部的意外异常也不外抛,而是记日志(loggeravada_eval.llm.tool)并返回ok=False、error="internal error: <类型>: <消息>"。sum/min/max/avg可直接传数:sum(1, 2, 3)(该工具默认不支持列表字面量,列表只能经变量传入:sum(values))。- 财务函数:
pct_change(new, old)、cagr(end, start, years)(均返回百分点)、ratio(a, b)、avg(...)。 - 千分位:逗号两侧无空格且分组合法(首组 1-3 位、其后每组 3 位)才视为千分位;逗号后带空格永远是参数分隔符(
max(1, 234))。 - 百分号:紧贴数字、且其后是结尾/空白/非操作数(
),*…)的%是百分号;10%3、10 % 3仍是取模。
安全
安全模型继承 simpleeval 并只加强不削弱:禁止 _/func_ 前缀属性、format/format_map
等危险方法、DISALLOW_FUNCTIONS、模块访问(需显式 ModuleWrapper)、lambda / import / 赋值。
资源耗尽防护在分配或计算之前按估算值拦截(修复了 simpleeval 中
'%999999999d' % 1、f"{1:999999999}"、"a".center(999999999)、4000000 ** 4000000、
'%d' % 1e999999 等先分配/计算再检查的问题)。上限为 avada_eval.evaluator 的模块级常量,调用时读取:
| 常量 | 默认 | 作用 |
|---|---|---|
MAX_STRING_LENGTH |
100000 | 构造出的字符串/序列长度(容器按嵌套元素总数计) |
MAX_FORMAT_WIDTH |
10000 | 格式化 width/precision 与 center/ljust/rjust/zfill/expandtabs 宽度 |
MAX_INT_BITS |
15000 | 任何 int 的位数 |
MAX_POWER / MAX_SHIFT |
4000000 / 10000 | ** 底数与指数、移位量 |
MAX_POWER_BASE_DIGITS |
1000 | Decimal 小数次幂的底数位数 |
MAX_COMPREHENSION_LENGTH |
10000 | 推导式迭代次数(EvalWithCompoundTypes) |
import avada_eval.evaluator as evaluator
evaluator.MAX_FORMAT_WIDTH = 1000 # 与 simpleeval 一样,直接改模块属性
完整排查清单与拦不住的部分(表达式长度、推导式总内存、自定义 context 等)见 ADR 0003。 对不可信输入,仍建议限制表达式长度,并在带超时与内存上限的子进程中求值。
命令行
avada "0.1 + 0.2"
avada "round(x * 3, 1)" -v x=0.05 --rounding ROUND_HALF_UP
avada "a + 1,000" -v a=1.5 --json
开发
uv sync 后,make fmt 做格式化,./ci.sh(从仓库根运行)是唯一的零警告质量门:
ruff format/check → mypy --strict → 结构检查 → 文档漂移 → pytest。
许可
MIT,见 LICENSE(保留 simpleeval 原版权声明)。
Metadata
Release files for avada-eval 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| avada_eval-0.1.1.tar.gz | 104.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| avada_eval-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 140.0 kB
Release files / avada_eval-0.1.1.tar.gz
| Download URL | avada_eval-0.1.1.tar.gz |
|---|---|
| Size | 104.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
871764cd80d2c82f087f7c7e4f28ab6975d764a96706e73158fd765e76f671ae
|
|
BLAKE2b-256 checksum How to use checksums |
6ac013406daf4886cc2fa10ec6e8e9a17d1ab98eb4de8bf51bfa5796bccc66c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Release files / avada_eval-0.1.1-py3-none-any.whl
| Download URL | avada_eval-0.1.1-py3-none-any.whl |
|---|---|
| Size | 35.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
108c8aee833d69efffadc2e576fe4dae443589eb6e431a30aaaf383ea0c0ac99
|
|
BLAKE2b-256 checksum How to use checksums |
f83102bdc7b2c1495c9ca214f80cbf7d297c9e0fcd265981ab43a101f54b48e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|