Stripe 面试真题:实现一个简化版 Radar 反欺诈规则引擎 – 一亩三分地 – VO 辅助 – 代面试

Stripe 的 Radar 用于识别和拦截高风险交易。这道题要求实现一个简化版规则引擎,根据交易数据和商户配置的规则,判断一笔交易应该被接受还是拦截。

英文原题

Stripe's Radar product is designed to fight transaction fraud;
it integrates many data points per transaction and allows merchants
to define rules that use those data points to block transactions
with a high likelihood of being fraud.

For this problem, we'll be implementing a modified subset of Radar's
query language, which is used for defining those rules.

需要实现的函数:

function should_accept_transaction(
    transaction: dictionary[string, string],
    rules: array[string],
) -> boolean

其中:

  • transaction 保存一笔交易的字段和值;
  • rules 是按顺序执行的规则列表;
  • 返回 true 表示接受交易;
  • 返回 false 表示拦截交易。

Part 1:ACCEPT、BLOCK 和字符串比较

第一部分需要支持两种规则:

ACCEPT if (...)
BLOCK if (...)

条件中暂时只需要支持字符串相等判断:

=

例如:

ACCEPT if (:merchant_name: = "Not A Fraudster")
BLOCK if ("Fraudcard" = :card_brand:)

交易数据:

{
  merchant_name: "Not A Fraudster",
  card_brand: "Visa"
}

第一条规则成立,因此结果是 ACCEPT,函数返回 true

这里需要注意,字段变量使用冒号包围:

:merchant_name:

字符串常量使用双引号:

"Not A Fraudster"

等号两侧的顺序并不固定,下面两种写法都应该能够处理:

:card_brand: = "Visa"
"Visa" = :card_brand:

Part 2:支持布尔变量、AND 和 OR

第二部分在原有功能上增加布尔条件,并支持:

AND
OR

语法示例:

(:<boolean_variable>: <AND/OR> :<boolean_variable>:)

规则:

BLOCK if (:known_stolen_card:)
BLOCK if (:large_amount: AND :from_different_country:)

交易一:

{
  known_stolen_card: true,
  large_amount: false,
  from_different_country: false
}

第一条规则成立,因此交易被拦截。

交易二:

{
  known_stolen_card: false,
  large_amount: true,
  from_different_country: true
}

第二条规则成立,因此交易同样被拦截。

交易三:

{
  known_stolen_card: false,
  large_amount: true,
  from_different_country: false
}

两条规则都不成立,因此默认接受交易。


核心实现思路

这道题可以拆成三个部分。

1. 解析规则动作

每条规则都以 ACCEPT ifBLOCK if 开头。

ACCEPT if (...)
BLOCK if (...)

先提取动作,再取出括号中的条件表达式。

action = ACCEPT / BLOCK
condition = 括号中的内容

2. 计算条件表达式

第一部分需要支持:

:left: = "value"
"value" = :right:

解析操作数时,可以统一设计一个 resolveOperand

如果是 :field:,从 transaction 中取值
如果是 "value",返回字符串常量

然后比较两边解析后的结果。

第二部分增加:

:boolean_field:
:left_boolean: AND :right_boolean:
:left_boolean: OR :right_boolean:

在题目当前范围内,可以先处理单个布尔变量和一个二元 AND/OR 表达式,不需要一开始就实现完整的编译器。

3. 按顺序执行规则

规则是有顺序的,通常采用“第一条匹配规则生效”的方式:

for rule in rules:
    action, condition = parse(rule)

    if evaluate(condition, transaction):
        return action == ACCEPT

return true

如果没有任何规则命中,则默认接受交易。


推荐的代码结构

不要把字符串切割、字段取值和规则执行全部写在一个函数里,可以拆成:

should_accept_transaction()
parse_rule()
evaluate_condition()
resolve_operand()
evaluate_boolean()

这种结构方便在后续增加新的操作符,例如:

!=
>
<
IN
NOT

Part 2 也要求原有字符串比较功能继续正常工作,因此解析和执行逻辑分离会更容易维护。


容易出错的地方

规则顺序

假设同时存在:

ACCEPT if (:trusted_user:)
BLOCK if (:high_risk_country:)

如果两个条件都成立,结果取决于哪条规则先出现,不能先把所有 BLOCK 规则单独执行。

等号左右两侧都可能是变量或常量

不要只处理:

:field: = "value"

题目示例中已经出现:

"value" = :field:

更稳妥的方式是让等号两侧都通过同一个操作数解析函数。

字符串中可能包含空格

下面的值不能简单按照空格切割:

"Not A Fraudster"

可以通过正则表达式、状态扫描,或者先定位等号,再分别解析左右两侧。

字段不存在

当规则引用了交易中不存在的字段时,需要提前定义行为。常见处理方式是让该条件返回 false,而不是直接抛出异常。

布尔类型

第一部分的接口写的是:

dictionary[string, string]

但第二部分的交易数据已经出现 truefalse

实际实现时可以让交易值支持 string | boolean,或者明确将 "true""false" 转换为布尔值,避免直接使用字符串的真值判断。

例如在 Python 中:

bool("false")

结果仍然是 True,这是一个常见错误。

Part 2 不能破坏 Part 1

加入 ANDOR 后,字符串相等、ACCEPTBLOCK 和默认接受逻辑都必须继续工作。测试时应该保留第一部分的全部用例。


面试官主要关注什么

这道题的重点不只是解析字符串,而是观察候选人如何逐步扩展一个小型规则语言:

  • 是否能准确处理规则优先级和默认行为;
  • 是否把解析逻辑与执行逻辑分开;
  • 是否考虑字段缺失、类型转换和非法规则;
  • 是否能够在 Part 2 中兼容 Part 1;
  • 是否为后续增加更多操作符保留扩展空间。

如果题目继续扩展到多层括号、NOT 以及混合表达式,就可以进一步引入 tokenizer、AST 和递归下降解析器。但在当前题目范围内,没有必要过度设计。


建议测试用例

至少覆盖以下情况:

1. ACCEPT 条件成立
2. BLOCK 条件成立
3. 没有任何规则成立
4. 多条规则同时成立
5. 字符串常量位于等号左侧
6. 字段不存在
7. 单个布尔变量
8. AND 的两种结果
9. OR 的两种结果
10. Part 2 中继续执行字符串比较规则

这是一道典型的增量式面试题。第一部分先完成最小规则引擎,第二部分再增加类型和逻辑运算。实现时控制好模块边界,比一开始写一个复杂的通用 parser 更重要。


csoahelp 提供海外科技公司面试的实时文本辅助和 Mock 面试服务,可针对 Stripe、Google、Amazon、OpenAI 等公司的 Coding、System Design 和 Behavioral Interview 进行模拟与复盘。

我们也有代面试,面试辅助,OA代写等服务助您早日上岸~

Leave a Reply

Your email address will not be published. Required fields are marked *