低代码平台选型:四问决策树
先问数据能不能出网,再问谁来运维,然后问编排够不够用,最后才算钱——顺序不能换,因为成本能谈,合规不能谈。
30″30 秒看懂低代码平台选型
同一套 AI 应用,可以租一间精装房、买毛坯房自己装、也可以买地自己盖。三种都能住人,区别在于:你能不能拆墙、东西放进屋房东看不看得见、以及哪天想搬家搬不搬得动。
租房就是订阅在线平台:拎包入住,当天开工,但家具是房东的,你放进屋的东西房东都看得见,房东涨租或停租你就得搬。买毛坯自己装是开源自部署:房子在你名下,东西放屋里没人看得见,想改哪面墙改哪面墙——代价是水电坏了没有物业,得自己修。买地自己盖是全自研框架:想盖成什么样就什么样,但每一根钢筋都要自己买,工期以季度计。
| 比喻里的说法 | 对应的技术路线 | 真正决定选它的那件事 |
|---|---|---|
| 租一间精装房 | 订阅在线平台 | 要得急、量不大、数据本来就可以公开 |
| 买毛坯房自己装 | 开源自部署 | 数据不许出网,且有人能长期接住运维 |
| 买地自己盖 | 全自研框架 | 需求已经超出拖拽编排能表达的范围 |
| 房东能看见你放了什么 | 数据边界 | 选型里唯一的一票否决项,排在成本前面 |
| 搬家要搬多少东西 | 平台锁定度 | 进场之前就该估出来的数字 |
| 房产证背面的使用限制 | 许可证附加条款 | 「开源」推不出「能拿去卖」 |
这一页不教你点哪个按钮。平台的界面三个月就会变一次,但上面这套判断顺序不会变。学会它,换到任何一个新平台,你都能在半小时内判断「该不该用它」。
01概念:低代码平台到底替你做了什么
它省掉的是哪部分工作、三条路线各自是什么、以及为什么「界面怎么点」不值得背
1.1 一句话定义
AI 低代码平台,是把「调用大模型做一件事」这个流程里的胶水代码,换成了可视化编排。
不用低代码平台时,你要自己写:接收请求、拼提示词、调模型接口、解析返回、判断要不要调工具、执行工具、把结果回灌、处理流式输出、记录会话、做错误重试。这十件事里,只有「拼提示词」和「执行工具」是业务逻辑,其余八件每个项目都长得一样。低代码平台把那八件封成了节点,你拖进画布连上线就行。
1.2 三条路线的分界线在哪
市面上的方案很多,但按「谁持有你的数据、谁决定你能用什么」这两个问题一划,只有三类:
| 路线 | 程序跑在哪 | 数据存在哪 | 你能改什么 |
|---|---|---|---|
| 订阅在线平台 | 平台的机器 | 平台的库 | 只能改平台开放给你的配置项 |
| 开源自部署 | 你的机器 | 你的库 | 配置、模型、甚至源码,受许可证约束 |
| 全自研框架 | 你的机器 | 你的库 | 全部,因为全是你写的 |
注意中间那一栏:同一个开源项目,既可以用它的在线托管版,也可以拉下来自己部署。这两种用法虽然界面一模一样,但在选型上属于完全不同的两条路——托管版的数据在对方手里,自部署的数据在你手里。很多人在这里混淆,以为「我用的是开源的所以数据安全」,其实用的是人家的托管服务。
1.3 为什么这一页不讲「界面怎么点」
因为界面是这套知识里最不值钱、也最容易过期的部分。同一个平台,半年内改版两次是常态:按钮换位置、菜单换名字、免费额度换算法。把「点左上角第三个按钮」背下来,三个月后就是错的。
真正不变的是下面这些:
这个平台能不能连你的内网数据库、能不能换模型、能不能导出你的编排结构。这些由架构决定,改版改不掉。
一次调用会把哪些东西送出你的网络。这个由部署形态决定,跟界面无关。
是按调用量线性涨,还是先付一笔固定门槛。这决定了在什么规模上该换路线。
哪些资产能带走、哪些带不走。这个在你签约之前就已经定了。
所以后面几页在讲具体平台时,操作步骤都会写成「找到 X 功能」而不是「点击某个位置的按钮」。你要建立的是「我需要一个能做 X 的功能,去这类平台里找它」的能力,而不是某一版界面的肌肉记忆。
02原理:四问决策树与它背后的排序逻辑
为什么数据边界排第一、为什么成本排最后、以及每一问该怎么问才问得准
2.1 决策树全貌
选型不是把三条路线的优缺点列成表然后「综合考虑」——那样永远得不出结论。正确做法是按固定顺序问四个问题,前面的问题一旦触发就直接出结果,不再往下走。
2.2 第 1 问:数据允许离开自有网络吗
这是唯一一个「否」就砍掉整条分支的问题,所以排第一。
问这一问时最容易犯的错,是只想到「用户输入的那句话」。实际上一次平台调用携带的东西远不止于此:
| 载荷 | 敏感级别 | 能不能靠改提示词避免 |
|---|---|---|
| 用户输入的原始问题 | internal | 不能,这是输入本身 |
| 知识库命中的文档分片 | confidential | 不能,不给分片就没法答 |
| 业务数据库查询结果 | regulated | 不能,这正是要它处理的数据 |
| 历史多轮会话 | confidential | 不能,除非放弃多轮 |
| 用户上传的原始文件 | confidential | 不能 |
| 内部接口地址与字段名 | internal | 能,本来就不该塞进提示词 |
| 调试用的完整堆栈 | internal | 能,上线前就该关掉 |
2.3 第 2 问:有人能长期承接运维吗
这一问筛掉的是「热情上头自建,半年后无人敢升级」的项目。自部署不是「装好就完了」,它是一份长期订阅——只不过订阅费付的是人的时间而不是钱。
判断标准很具体:出问题时,有没有一个明确的人会在当天响应?如果这个人不存在,或者他同时还背着五个别的系统,那自部署的实际形态会是:装好了、跑起来了、然后冻结在那个版本上,因为没人敢动。
2.4 第 3 问:需求超出拖拽编排的表达能力了吗
可视化编排擅长表达有向、分支有限、每步职责清晰的流程。它不擅长表达:动态生成的流程结构、需要精细控制并发与重试策略的调度、深度嵌套的状态机。
怎么判断?看你在画布上是不是开始用一堆条件节点模拟 if-else 嵌套,或者不停地往「代码节点」里塞逻辑。一旦画布变成「用鼠标写代码」,平台就已经从助力变成负担了——这时候直接写代码反而更快更好维护。
2.5 第 4 问:量小且要得急吗
到这一步才轮到成本和上线时间。前三问都通过,说明三条路线技术上都可行,这时候比的才是性价比。
决策树的代码实现只有几十行,顺序一目了然:
"""路线判定器:把选型问题压成一棵可执行的决策树。
顺序是刻意设计的 —— 先问数据边界,再问团队能力,最后才问成本。
把成本放最后,是因为成本能谈,合规不能谈。
纯标准库,直接 python3 route_decide.py 就能跑。
"""
SAAS = "订阅在线平台"
SELF_HOST = "开源自部署"
SELF_BUILT = "全自研框架"
def decide(case):
"""按固定顺序问四个问题,返回 (推荐路线, 决定性理由)。
case 是一个字典,字段含义见下方 CASES。
"""
# 第一问:数据能不能离开自己的网络边界
# 这是唯一一个「否」就直接砍掉整条分支的问题
if not case["data_may_leave_network"]:
if case["needs_deep_customization"]:
return SELF_BUILT, "数据不许出网 + 需要深度定制,只剩自己搭这一条路"
return SELF_HOST, "数据不许出网,排除一切托管平台;编排能力够用则自部署"
# 第二问:有没有人能接住运维
# 没人运维的自部署,半年后一定变成没人敢升级的黑盒
if not case["has_ops_capacity"]:
return SAAS, "数据可出网且无人承接运维,自部署会在升级时失控"
# 第三问:现有平台的编排能力够不够
if case["needs_deep_customization"]:
return SELF_BUILT, "需求超出拖拽编排的表达能力,平台会变成负担"
# 第四问:这才轮到成本与速度
if case["monthly_calls"] < 100_000 and case["time_to_market_weeks"] <= 4:
return SAAS, "量不大且要得急,订阅平台的起步速度不可替代"
return SELF_HOST, "量已上来且有运维能力,自部署在可控性上更划算"
CASES = {
"电商批量生成营销文案": {
"data_may_leave_network": True, # 商品文案本就是要公开的
"has_ops_capacity": False,
"needs_deep_customization": False,
"monthly_calls": 30_000,
"time_to_market_weeks": 2,
},
"律所法律问答(连业务库)": {
"data_may_leave_network": False, # 案卷与客户资料
"has_ops_capacity": True,
"needs_deep_customization": False,
"monthly_calls": 20_000,
"time_to_market_weeks": 8,
},
"医院内部病历问答": {
"data_may_leave_network": False,
"has_ops_capacity": True,
"needs_deep_customization": True, # 要接院内 HIS,权限模型复杂
"monthly_calls": 50_000,
"time_to_market_weeks": 16,
},
"运营部门内部提效小工具": {
"data_may_leave_network": True,
"has_ops_capacity": False,
"needs_deep_customization": False,
"monthly_calls": 5_000,
"time_to_market_weeks": 1,
},
"面向公众的核心对话产品": {
"data_may_leave_network": True,
"has_ops_capacity": True,
"needs_deep_customization": True,
"monthly_calls": 3_000_000,
"time_to_market_weeks": 24,
},
}
def main():
for name, case in CASES.items():
route, why = decide(case)
print("%-22s -> %-8s %s" % (name, route, why))
# 把「数据不出网」这条规则钉死:无论其他条件怎么变,结论都不会是订阅平台
for name, case in CASES.items():
if not case["data_may_leave_network"]:
route, _ = decide(case)
assert route != SAAS, "%s 的数据不许出网,不该推荐订阅平台" % name
print("\n校验通过:数据不出网的场景,没有一个被推荐到订阅平台。")
if __name__ == "__main__":
main()
注意最后那段 assert:它把「数据不出网的场景绝不能推荐托管平台」这条规则钉死在代码里。写选型逻辑时加上这类断言,能防止后续改权重时不小心破坏硬约束。
实跑五个典型场景,结果是这样的:
电商批量生成营销文案 -> 订阅在线平台 数据可出网且无人承接运维,自部署会在升级时失控
律所法律问答(连业务库) -> 开源自部署 数据不许出网,排除一切托管平台;编排能力够用则自部署
医院内部病历问答 -> 全自研框架 数据不许出网 + 需要深度定制,只剩自己搭这一条路
运营部门内部提效小工具 -> 订阅在线平台 数据可出网且无人承接运维,自部署会在升级时失控
面向公众的核心对话产品 -> 全自研框架 需求超出拖拽编排的表达能力,平台会变成负担
校验通过:数据不出网的场景,没有一个被推荐到订阅平台。
2.6 为什么不是「加权打分」就完事
加权打分有用,但它只能用在第 4 问之后。如果一上来就给四个维度打分求和,合规这种一票否决项就会被其他维度的高分稀释掉——数据边界得 3 分,但成本和速度各得 9 分,加权一算托管平台还赢了,这个结论显然是错的。
打分的正确用法是:在硬约束筛完之后,比较剩下的候选。同一组分数换一组权重,结论就会翻转,这恰恰说明了为什么不同公司对同一道题给出不同答案:
"""加权打分:把「感觉哪个好」变成一个可复算的数字。
四个维度不是并列的,权重由业务场景决定 —— 这正是同一道题不同公司
给出不同答案的原因。改权重比改分数更能反映真实立场。
纯标准库,直接 python3 score_matrix.py 就能跑。
"""
# 三条路线在四个维度上的表现分(0-10,越高越好)
# 打分依据写在注释里,换了场景要自己重打,不要照抄
ROUTES = {
"订阅在线平台": {
"data_compliance": 3, # 数据要过平台,跨境/行业监管场景直接出局
"cost_at_start": 9, # 起步几乎零成本,不用买机器也不用招运维
"iteration_speed": 9, # 拖拽即改,改完立刻能试
"controllability": 3, # 模型、插件、配额都由平台定,说停就停
},
"开源自部署": {
"data_compliance": 9, # 数据落在自己机房,边界清晰
"cost_at_start": 4, # 机器 + 运维 + 排障时间都是真金白银
"iteration_speed": 7, # 仍是拖拽编排,但升级、修复要自己扛
"controllability": 8, # 能改源码、能换模型,受许可证附加条款约束
},
"全自研框架": {
"data_compliance": 9, # 想怎么隔离就怎么隔离
"cost_at_start": 2, # 每个轮子都要自己造,人力成本最高
"iteration_speed": 3, # 改一个流程要走完整的开发测试上线
"controllability": 10, # 没有任何外部约束
},
}
# 四类典型业务场景的权重(四项之和固定为 1.0)
SCENARIOS = {
"个人/小团队快速验证": {
"data_compliance": 0.10,
"cost_at_start": 0.40,
"iteration_speed": 0.40,
"controllability": 0.10,
},
"金融医疗等强监管业务": {
"data_compliance": 0.55,
"cost_at_start": 0.10,
"iteration_speed": 0.10,
"controllability": 0.25,
},
"企业内部提效工具": {
"data_compliance": 0.30,
"cost_at_start": 0.25,
"iteration_speed": 0.30,
"controllability": 0.15,
},
"对外核心产品": {
"data_compliance": 0.25,
"cost_at_start": 0.10,
"iteration_speed": 0.20,
"controllability": 0.45,
},
}
def score(route_name, weights):
"""一条路线在给定权重下的加权总分。"""
dims = ROUTES[route_name]
return sum(dims[k] * weights[k] for k in weights)
def rank(weights):
"""按加权总分从高到低排序,返回 [(路线, 分数), ...]。"""
pairs = [(name, score(name, weights)) for name in ROUTES]
return sorted(pairs, key=lambda x: x[1], reverse=True)
def main():
for scenario, weights in SCENARIOS.items():
# 权重必须归一,否则不同场景的分数没法横向比
total_w = sum(weights.values())
assert abs(total_w - 1.0) < 1e-9, "%s 权重之和为 %s,应为 1.0" % (scenario, total_w)
board = rank(weights)
print("\n【%s】" % scenario)
for i, (name, sc) in enumerate(board, 1):
mark = " <== 推荐" if i == 1 else ""
print(" %d. %-12s %.2f%s" % (i, name, sc, mark))
# 第一名和第二名差距太小,说明这道题本身没有明显答案,
# 该去补业务信息而不是硬选
gap = board[0][1] - board[1][1]
if gap < 0.5:
print(" ⚠ 前两名仅差 %.2f,属于「怎么选都行」,别在这里纠结" % gap)
if __name__ == "__main__":
main()
【个人/小团队快速验证】
1. 订阅在线平台 7.80 <== 推荐
2. 开源自部署 6.10
3. 全自研框架 3.90
【金融医疗等强监管业务】
1. 开源自部署 8.05 <== 推荐
2. 全自研框架 7.95
3. 订阅在线平台 4.20
⚠ 前两名仅差 0.10,属于「怎么选都行」,别在这里纠结
【企业内部提效工具】
1. 开源自部署 7.00 <== 推荐
2. 订阅在线平台 6.30
3. 全自研框架 5.60
【对外核心产品】
1. 开源自部署 7.65 <== 推荐
2. 全自研框架 7.55
3. 订阅在线平台 4.80
⚠ 前两名仅差 0.10,属于「怎么选都行」,别在这里纠结
03最小可跑:三十行算清一次选型
把「感觉哪个好」变成一个能复算、能被质疑、能被改参数推翻的数字
选型会上最没有说服力的一句话是「我觉得自部署更划算」。有说服力的是:「按这组参数,第 N 个月起自部署更便宜;如果调用量增速低于 X,那么三年内都不会反超。」后者能被验证,也能被推翻——这正是它可信的原因。
3.1 先算数据边界,这一步不用钱
在算钱之前先跑这个,因为它可能直接让后面的成本测算失去意义:
"""数据边界审计:一条请求到底把什么送出了公司网络。
选型讨论里最常见的错觉是「我们只发了一个问题过去」。
实际上一次平台调用会携带:用户原话、命中的知识库分片、
数据库查询结果、历史会话、文件原文 —— 任何一项越界都算越界。
纯标准库,直接 python3 data_boundary_audit.py 就能跑。
"""
# 敏感级别:越高越不能离开自有网络
LEVEL = {
"public": 0, # 本来就对外公开
"internal": 1, # 公司内部可见
"confidential": 2, # 限定人员可见
"regulated": 3, # 受行业或法律强监管
}
# 一次平台调用实际会携带的载荷清单
PAYLOAD = [
# (载荷项, 敏感级别, 是否真的必须送出去)
("用户输入的原始问题", "internal", True),
("知识库命中的文档分片", "confidential", True),
("业务数据库查询结果", "regulated", True),
("历史多轮会话", "confidential", True),
("用户上传的原始文件", "confidential", True),
("内部系统的接口地址与字段名", "internal", False),
("调试用的完整堆栈", "internal", False),
]
# 这套系统允许离开网络的最高级别
ALLOWED_MAX = LEVEL["internal"]
def audit(payload, allowed_max):
"""返回 (越界项, 可裁掉的项)。"""
violations, trimmable = [], []
for name, lv, required in payload:
if LEVEL[lv] > allowed_max:
violations.append((name, lv, required))
if not required:
trimmable.append(name)
return violations, trimmable
def main():
violations, trimmable = audit(PAYLOAD, ALLOWED_MAX)
print("允许出网的最高敏感级别:internal\n")
print("越界载荷:")
for name, lv, required in violations:
tag = "业务必需" if required else "可直接删掉"
print(" ❌ %-22s %-13s %s" % (name, lv, tag))
print("\n无论如何都该裁掉的:")
for name in trimmable:
print(" ✂ %s" % name)
must_stay = [v for v in violations if v[2]]
print()
if must_stay:
print("结论:有 %d 项越界载荷是业务必需的,删不掉。" % len(must_stay))
print("这意味着「换个提示词就合规了」是幻想 —— 要么把这些数据")
print("留在自己网络里(自部署),要么先做脱敏再出网,二选一。")
else:
print("结论:越界项都可裁剪,裁完即可使用托管平台。")
# 只要还有业务必需的越界项,就不允许得出「可以用托管平台」的结论
assert must_stay, "示例数据本就包含 regulated 级别的必需载荷"
if __name__ == "__main__":
main()
实跑输出:
允许出网的最高敏感级别:internal
越界载荷:
❌ 知识库命中的文档分片 confidential 业务必需
❌ 业务数据库查询结果 regulated 业务必需
❌ 历史多轮会话 confidential 业务必需
❌ 用户上传的原始文件 confidential 业务必需
无论如何都该裁掉的:
✂ 内部系统的接口地址与字段名
✂ 调试用的完整堆栈
结论:有 4 项越界载荷是业务必需的,删不掉。
这意味着「换个提示词就合规了」是幻想 —— 要么把这些数据
留在自己网络里(自部署),要么先做脱敏再出网,二选一。
结论那句话是这段代码的价值所在:有 1 项越界载荷是业务必需的,删不掉。到这里托管平台已经出局,后面的成本对比只需要在自部署和自研之间做。
3.2 再算三年总持有成本
TCO 模型的核心不是求出一个绝对数字——你的报价和我的不一样,绝对数字没有可比性。它的核心是找两条曲线的交点:
"""三条路线的三年总持有成本(TCO)对比模型。
结论不是「哪条便宜」,而是「在多长的时间尺度上哪条便宜」——
订阅制起步便宜但按量线性增长,自部署有一笔固定门槛但边际成本低。
两条曲线一定有交点,找到那个交点,选型就有了量化依据。
所有单价都是占位参数,必须换成自己实际询价得到的数字再算。
纯标准库,直接 python3 tco_model.py 就能跑。
"""
MONTHS = 36
# —— 占位参数:用你自己的真实报价替换 ——
CALLS_PER_MONTH_START = 20_000 # 首月调用量
MONTHLY_GROWTH = 0.08 # 调用量月增长率
PRICE_PER_CALL_SAAS = 0.02 # 订阅平台每次调用的综合单价(元)
PLATFORM_BASE_FEE = 0 # 订阅平台固定月费(元)
SERVER_MONTHLY = 3_000 # 自部署:一台够用的机器月租(元)
OPS_MONTHLY = 6_000 # 自部署:分摊到这套系统的运维人力(元)
SETUP_ONCE = 40_000 # 自部署:一次性搭建与调优投入(元)
PRICE_PER_CALL_SELF = 0.006 # 自部署:仍要付给模型厂商的推理单价(元)
DEV_MONTHLY_SELFBUILT = 25_000 # 全自研:持续投入的研发人力(元)
SETUP_ONCE_SELFBUILT = 150_000 # 全自研:从零到可用的一次性投入(元)
def calls_in_month(m):
"""第 m 个月(从 0 开始)的调用量。"""
return CALLS_PER_MONTH_START * ((1 + MONTHLY_GROWTH) ** m)
def cumulative():
"""逐月累计三条路线的总成本,返回 {路线: [每月累计, ...]}。"""
saas, self_host, self_built = [], [], []
a = b = c = 0.0
b += SETUP_ONCE
c += SETUP_ONCE_SELFBUILT
for m in range(MONTHS):
n = calls_in_month(m)
a += PLATFORM_BASE_FEE + n * PRICE_PER_CALL_SAAS
b += SERVER_MONTHLY + OPS_MONTHLY + n * PRICE_PER_CALL_SELF
c += DEV_MONTHLY_SELFBUILT + n * PRICE_PER_CALL_SELF
saas.append(a)
self_host.append(b)
self_built.append(c)
return {"订阅在线平台": saas, "开源自部署": self_host, "全自研框架": self_built}
def crossover(series_a, series_b):
"""找 a 由便宜变贵的那个月(1-based);始终不反超返回 None。"""
for m in range(len(series_a)):
if series_a[m] > series_b[m]:
return m + 1
return None
def main():
data = cumulative()
print("调用量:首月 %s 次,月增 %.0f%%,第 %d 月约 %s 次" % (
format(CALLS_PER_MONTH_START, ","), MONTHLY_GROWTH * 100,
MONTHS, format(int(calls_in_month(MONTHS - 1)), ",")))
print()
print("%-6s %14s %14s %14s" % ("月份", "订阅在线平台", "开源自部署", "全自研框架"))
for m in (0, 5, 11, 17, 23, 35):
print("%-6s %14s %14s %14s" % (
"第%d月" % (m + 1),
format(int(data["订阅在线平台"][m]), ","),
format(int(data["开源自部署"][m]), ","),
format(int(data["全自研框架"][m]), ",")))
print()
cp = crossover(data["订阅在线平台"], data["开源自部署"])
if cp:
print("订阅 vs 自部署:第 %d 个月起,自部署开始更划算" % cp)
else:
print("订阅 vs 自部署:三年内订阅始终更便宜,别为了省钱去自部署")
cp2 = crossover(data["订阅在线平台"], data["全自研框架"])
if cp2:
print("订阅 vs 全自研:第 %d 个月起,全自研开始更划算" % cp2)
else:
print("订阅 vs 全自研:三年内全自研都收不回成本,"
"选它的理由只能是可控性而不是省钱")
if __name__ == "__main__":
main()
用文件里那组示例参数实跑,得到一个反直觉但诚实的结果:
调用量:首月 20,000 次,月增 8%,第 36 月约 295,706 次
月份 订阅在线平台 开源自部署 全自研框架
第1月 400 49,120 175,120
第6月 2,934 94,880 300,880
第12月 7,590 150,277 452,277
第18月 14,980 206,494 604,494
第24月 26,705 264,011 758,011
第36月 74,840 386,452 1,072,452
订阅 vs 自部署:三年内订阅始终更便宜,别为了省钱去自部署
订阅 vs 全自研:三年内全自研都收不回成本,选它的理由只能是可控性而不是省钱
3.3 参数怎么改,结论就怎么变
这个模型的用法是改参数看结论翻不翻。几个值得试的方向:
| 改什么 | 改成什么 | 结论会怎么变 |
|---|---|---|
CALLS_PER_MONTH_START | 调到几十万级 | 订阅的线性增长开始吃不消,交叉点提前到三年内 |
MONTHLY_GROWTH | 从 0.08 提到 0.20 | 订阅曲线急剧上翘,交叉点大幅提前 |
OPS_MONTHLY | 改成你真实的人力分摊 | 这是自部署最容易被低估的一项,改完往往翻倍 |
PRICE_PER_CALL_SAAS | 换成你实际询到的价 | 示例值只是占位,必须替换 |
04完整案例:五个场景走一遍决策树
同一棵树,五种业务,五个不同结论——看清楚是哪一问决定的
4.1 电商批量生成营销文案 → 订阅在线平台
业务:几万个商品,要批量生成标题和卖点文案,运营同学自己维护。
走树:第 1 问,商品文案本来就是要公开挂在页面上的,数据可以出网 → 通过。第 2 问,运营部门没有专职运维 → 在这里出结果。
4.2 律所法律问答(连业务库)→ 开源自部署
业务:把所里的案卷、合同模板做成知识库,律师内部问答。
走树:第 1 问,案卷和客户资料属于受保密义务约束的材料,不能出网 → 直接出结果,托管平台全部出局。接着问定制深度:标准的知识库检索 + 问答,拖拽编排完全能表达 → 开源自部署。
注意这个场景里成本根本没被问到。哪怕托管平台免费,它也进不了候选名单。这就是把数据边界排第一的意义。
4.3 医院内部病历问答 → 全自研框架
业务:接院内 HIS 系统,医生查询历史病历,要按科室和职级做权限隔离。
走树:第 1 问,病历是典型的 regulated 级数据 → 托管出局。第 3 问,要接内网 HIS、要做细粒度权限模型 → 超出拖拽编排的表达能力,落到全自研。
| 需求 | 编排能不能表达 | 原因 |
|---|---|---|
| 按科室过滤知识库 | 勉强能 | 多数平台支持给检索加过滤条件 |
| 按职级决定字段可见性 | 不能 | 这是行列级权限,要在数据层做,不是流程层 |
| 每次查询留审计痕迹 | 不能 | 审计要求的完整性超出平台日志能给的 |
| 与 HIS 的会话态对齐 | 不能 | 需要深度嵌入既有系统的事务边界 |
4.4 运营部门内部提效小工具 → 订阅在线平台
业务:把周报汇总、会议纪要整理做成几个小工具,十来个人用。
走树:数据可出网、无人运维 → 订阅平台。这个场景的正确心态是「别想太多」:量只有几千次,一周内就要用上,为它做任何架构设计都是浪费。
4.5 面向公众的核心对话产品 → 全自研框架
业务:这就是公司的主产品,月调用量百万级以上。
走树:数据可出网、有运维能力,但第 3 问命中——核心产品一定会有大量非标需求:自定义的模型路由、按用户分层的降级策略、精细的成本控制、A/B 实验框架。这些全都不是拖拽能表达的。
4.6 五个案例横向看
| 场景 | 在第几问出结果 | 结论 | 决定性理由 |
|---|---|---|---|
| 电商文案 | 第 2 问 | 订阅在线平台 | 无人承接运维 |
| 律所问答 | 第 1 问 | 开源自部署 | 数据不许出网 |
| 医院病历 | 第 1+3 问 | 全自研框架 | 不出网且要深度定制 |
| 运营小工具 | 第 2 问 | 订阅在线平台 | 无人承接运维 |
| 核心对话产品 | 第 3 问 | 全自研框架 | 超出编排表达能力 |
五个案例里,只有零个是在第 4 问(成本)出的结果。这不是刻意安排——真实项目里,绝大多数选型在前三问就已经定了,成本只在剩余候选之间做微调。如果你的选型讨论一开场就在算钱,多半是前三问没问清楚。
05骨架模板:拿走就能用的四件套
锁定度测算、许可证闸门、平台存活体检、选型报告——把结论做成可以发给决策者的东西
5.1 锁定度测算:换一次要付多少
「大不了以后换」这句话必须先被量化,否则它就是一句安慰。做法是把资产分成两类:内容能带走,结构带不走。
"""锁定度体检:算一算「换掉这个平台」要付多少钱。
选型时人人都说「大不了以后换」,但真到要换的时候才发现:
提示词能带走,工作流的编排结构带不走;知识库的原始文档能带走,
切好的分片和向量带不走。锁定成本必须在进场之前就估出来。
纯标准库,直接 python3 lockin_score.py 就能跑。
"""
# 每一类资产:迁移难度权重(0-1,越高越难搬)
ASSET_WEIGHT = {
"提示词文本": 0.1, # 纯文本,复制即可
"原始文档": 0.1, # 自己本来就有备份
"工作流编排结构": 0.7, # 节点与连线是平台私有格式
"插件/工具调用配置": 0.6, # 每个平台的工具协议都不一样
"知识库分片与向量": 0.5, # 要重新灌一遍并重新调参
"会话历史": 0.8, # 托管在平台侧,导出接口往往不完整
"已发布的分发渠道": 0.9, # 绑定在平台账号上,等于重新上线
}
def lockin(assets):
"""assets: {资产类别: 规模系数},返回 (总分, 明细)。
规模系数用「相对工作量」表达即可,比如 10 条工作流就填 10。
"""
detail = []
total = 0.0
for name, size in assets.items():
w = ASSET_WEIGHT[name]
cost = w * size
total += cost
detail.append((name, size, w, cost))
detail.sort(key=lambda x: x[3], reverse=True)
return total, detail
def level(total):
if total < 10:
return "低 —— 随时可换,不必为锁定问题让步"
if total < 30:
return "中 —— 可换,但要预留一个迭代周期"
return "高 —— 事实上换不动了,进场前就得接受长期绑定"
def main():
# 一个跑了一年的中等规模项目的典型资产盘点
project = {
"提示词文本": 40,
"原始文档": 500,
"工作流编排结构": 18,
"插件/工具调用配置": 12,
"知识库分片与向量": 6,
"会话历史": 4,
"已发布的分发渠道": 3,
}
total, detail = lockin(project)
print("%-20s %8s %8s %10s" % ("资产类别", "规模", "难度", "迁移成本"))
print("-" * 50)
for name, size, w, cost in detail:
print("%-20s %8s %8.1f %10.1f" % (name, size, w, cost))
print("-" * 50)
print("锁定总分 %.1f —— %s" % (total, level(total)))
print("\n成本最高的三项:")
for name, _s, _w, cost in detail[:3]:
print(" • %s(%.1f)" % (name, cost))
print("降低锁定的办法不是不用平台,而是把这三项尽量留在自己手里:")
print(" 提示词与文档进自己的 git;会话历史落自己的库;")
print(" 分发渠道尽量走自己的域名而不是平台商店。")
if __name__ == "__main__":
main()
拿一个跑了一年的中等规模项目实跑:
资产类别 规模 难度 迁移成本
--------------------------------------------------
原始文档 500 0.1 50.0
工作流编排结构 18 0.7 12.6
插件/工具调用配置 12 0.6 7.2
提示词文本 40 0.1 4.0
会话历史 4 0.8 3.2
知识库分片与向量 6 0.5 3.0
已发布的分发渠道 3 0.9 2.7
--------------------------------------------------
锁定总分 82.7 —— 高 —— 事实上换不动了,进场前就得接受长期绑定
成本最高的三项:
• 原始文档(50.0)
• 工作流编排结构(12.6)
• 插件/工具调用配置(7.2)
降低锁定的办法不是不用平台,而是把这三项尽量留在自己手里:
提示词与文档进自己的 git;会话历史落自己的库;
分发渠道尽量走自己的域名而不是平台商店。
看最后三行给出的建议——降低锁定的办法不是不用平台,而是把最贵的三项攥在自己手里。提示词与文档进自己的 git,会话历史在调用时顺手写一份到自己的库,分发入口尽量走自己的域名而不是平台商店。做完这三件,同样的项目锁定分能压掉一大半。
5.2 许可证闸门:「开源」推不出「能拿去卖」
这是自部署路线上最容易踩的坑:看到 GitHub 上写着某个熟悉的协议名,就默认可以随便商用。实际上不少平台用的是「标准协议 + 附加条款」,而附加条款卡住的恰恰是最赚钱的用法。
"""许可证闸门:判断一份开源协议能不能支撑你打算做的生意。
「它是开源的」这句话不能直接推出「我可以拿它对外卖服务」。
很多平台用的是「标准协议 + 附加条款」,附加条款恰恰卡住的就是
最赚钱的那几种用法:多租户运营、去掉品牌标识、二次分发。
纯标准库,直接 python3 license_guard.py 就能跑。
"""
# 触发商业限制的典型措辞。命中不等于禁止,等于「必须人工读原文」
RISK_PATTERNS = {
"multi_tenant": [
"multi-tenant", "multi tenant", "multitenant", "多租户",
],
"branding": [
"logo", "copyright information", "版权信息", "品牌标识",
],
"commercial_license_required": [
"commercial license must be obtained",
"must obtain a commercial license",
"需要获得商业授权",
],
"network_copyleft": [
"affero", "agpl", "network use is distribution",
],
}
# 你打算怎么用它 —— 按实际业务改
INTENDED_USE = {
"对外提供多租户 SaaS": "multi_tenant",
"移除或替换前端品牌标识": "branding",
"作为闭源产品的一部分分发": "network_copyleft",
}
def scan(license_text):
"""返回 {风险类别: 命中的关键词列表}。"""
low = license_text.lower()
hits = {}
for kind, words in RISK_PATTERNS.items():
found = [w for w in words if w.lower() in low]
if found:
hits[kind] = found
return hits
def judge(license_text, intended_use=None):
"""把扫描结果对上你的使用意图,给出放行 / 复核清单。"""
intended_use = intended_use or INTENDED_USE
hits = scan(license_text)
print("命中的风险条款类别:")
if not hits:
print(" (无)—— 仍建议人工通读一遍,关键词法只能兜底不能定案")
for kind, words in hits.items():
print(" • %-28s 关键词 %s" % (kind, "/".join(words)))
print("\n对照你的使用意图:")
blocked = []
for use, kind in intended_use.items():
if kind in hits:
blocked.append(use)
print(" ❌ %-24s 受限 —— 必须走商业授权或放弃这种用法" % use)
else:
print(" ✅ %-24s 未命中限制条款" % use)
return blocked
# 一份「标准协议 + 附加条款」的典型样本,用于离线演示扫描逻辑
SAMPLE = """
Open Source License
This software is licensed under a modified version of the Apache License 2.0,
with the following additional conditions:
1. It may be utilized commercially, including as a backend service for other
applications. Should the conditions below be met, a commercial license must
be obtained from the producer:
a. Multi-tenant service: unless explicitly authorized in writing, you may not
use the source code to operate a multi-tenant environment.
b. LOGO and copyright information: you may not remove or modify the LOGO or
copyright information in the console or applications.
Apart from the specific conditions mentioned above, all other rights and
restrictions follow the Apache License 2.0.
"""
def main():
print("=== 扫描一份「标准协议 + 附加条款」的许可证 ===\n")
blocked = judge(SAMPLE)
print()
if blocked:
print("结论:有 %d 种打算好的用法被卡住 —— %s" % (len(blocked), "、".join(blocked)))
print("这类限制通常不影响企业自用,但会直接否掉「拿它改个皮对外卖」的方案。")
else:
print("结论:这份协议不阻碍当前列出的使用意图。")
if __name__ == "__main__":
main()
=== 扫描一份「标准协议 + 附加条款」的许可证 ===
命中的风险条款类别:
• multi_tenant 关键词 multi-tenant
• branding 关键词 logo/copyright information
对照你的使用意图:
❌ 对外提供多租户 SaaS 受限 —— 必须走商业授权或放弃这种用法
❌ 移除或替换前端品牌标识 受限 —— 必须走商业授权或放弃这种用法
✅ 作为闭源产品的一部分分发 未命中限制条款
结论:有 2 种打算好的用法被卡住 —— 对外提供多租户 SaaS、移除或替换前端品牌标识
这类限制通常不影响企业自用,但会直接否掉「拿它改个皮对外卖」的方案。
| 附加条款常见限制 | 对企业自用 | 对「改个皮对外卖」 |
|---|---|---|
| 禁止多租户运营 | 通常不影响 | 直接否掉 |
| 不得移除品牌标识与版权信息 | 影响很小 | 产品化受阻 |
| 特定条件下需另行商业授权 | 需逐条核对 | 要谈授权 |
5.3 平台存活体检:它半年后还有人维护吗
选型时最怕的不是功能少,而是半年后没人维护了。star 数只说明曾经火过,真正有信息量的是「最后一次提交距今多久」。
"""平台还活着吗:用 GitHub 公开接口给开源平台做一次体检。
选型时最怕的不是「功能少」,而是「半年后没人维护了」。
star 数只说明曾经火过,真正有信息量的是最后一次提交距今多久、
以及许可证到底是不是你以为的那个。
纯标准库(urllib),联网即可跑:
python3 platform_liveness.py
离线环境会打印网络错误并跳过,不会崩。
"""
import json
import urllib.request
import urllib.error
from datetime import datetime, timezone
# 想体检哪些平台就往这里加,格式是 GitHub 的 owner/repo
REPOS = [
"langgenius/dify",
"coze-dev/coze-studio",
"infiniflow/ragflow",
]
API = "https://api.github.com/repos/%s"
TIMEOUT = 15
def fetch(repo):
"""拉取仓库元信息;失败返回 None 而不是抛出,便于批量体检。"""
req = urllib.request.Request(
API % repo,
headers={
"Accept": "application/vnd.github+json",
# GitHub 对无 UA 的请求直接 403
"User-Agent": "platform-liveness-check",
},
)
try:
with urllib.request.urlopen(req, timeout=TIMEOUT) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as e:
# 403 绝大多数是匿名调用超了频率限制,不是仓库不存在
print(" [%s] HTTP %s %s" % (repo, e.code, e.reason))
except Exception as e:
print(" [%s] 请求失败: %s" % (repo, e))
return None
def days_since(iso_ts):
"""距今天数。iso_ts 形如 2026-09-18T10:50:01Z。"""
ts = datetime.strptime(iso_ts, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
return (datetime.now(timezone.utc) - ts).days
def verdict(idle_days):
"""把「多久没提交」翻译成一句能拿去汇报的判断。"""
if idle_days <= 30:
return "活跃,放心用"
if idle_days <= 90:
return "正常,观察即可"
if idle_days <= 365:
return "放缓,选型要问清楚路线图"
return "疑似停更,自建前先想好接盘成本"
def main():
print("%-26s %9s %12s %-26s %s" % (
"仓库", "star", "闲置天数", "许可证", "判断"))
print("-" * 96)
for repo in REPOS:
info = fetch(repo)
if not info:
continue
lic = info.get("license") or {}
spdx = lic.get("spdx_id") or "未标注"
idle = days_since(info["pushed_at"])
print("%-26s %9s %12d %-26s %s" % (
info["full_name"],
format(info["stargazers_count"], ","),
idle,
spdx,
verdict(idle),
))
# spdx_id 为 NOASSERTION 说明 GitHub 没能识别出标准许可证,
# 几乎都意味着作者在标准协议上加了附加条款 —— 必须翻原文
if spdx == "NOASSERTION":
print(" ⚠ 非标准许可证,务必读 LICENSE 原文,"
"附加条款常见于商用与多租户限制")
if __name__ == "__main__":
main()
| 闲置天数 | 判断 | 该做什么 |
|---|---|---|
| ≤ 30 天 | 活跃 | 放心用 |
| 31–90 天 | 正常 | 观察即可 |
| 91–365 天 | 放缓 | 选型时问清楚路线图 |
| > 365 天 | 疑似停更 | 自建前先想好接盘成本 |
NOASSERTION,说明平台方在标准协议上加了自定义条款,导致自动识别失败。这个信号比任何功能对比都重要——它意味着你必须去翻原文。
5.4 选型报告骨架:把结论变成能发出去的东西
前面几个脚本算出来的数字,最后要汇成一份决策者能读的东西。这份骨架里带 TODO 的地方全部必须替换成真实信息:
"""选型报告生成器(骨架模板)。
把前面几个脚本的结论汇总成一份能直接发给决策者的报告。
带 TODO 的地方是必须换成自己业务真实信息的,别拿示例值去汇报。
用法:
python3 selection_report.py > 选型结论.md
"""
from datetime import date
# ============ TODO: 以下全部替换为你自己的项目信息 ============
PROJECT = "TODO: 项目名称"
OWNER = "TODO: 决策负责人"
DEADLINE = "TODO: 期望上线时间"
# TODO: 按 data_boundary_audit.py 的审计结果填写
DATA_MAY_LEAVE_NETWORK = False
REGULATED_PAYLOAD = ["TODO: 列出受监管的必需载荷"]
# TODO: 按 route_decide.py 的判定结果填写
RECOMMENDED_ROUTE = "TODO: 订阅在线平台 / 开源自部署 / 全自研框架"
DECISIVE_REASON = "TODO: 一句话写清是哪个条件决定的"
# TODO: 按 tco_model.py 的测算填写
CROSSOVER_MONTH = None # 自部署反超订阅的月份;None 表示三年内不反超
THREE_YEAR_COST = "TODO: 三年总成本区间"
# TODO: 按 lockin_score.py 的测算填写
LOCKIN_SCORE = 0.0
LOCKIN_LEVEL = "TODO: 低 / 中 / 高"
# TODO: 按 platform_liveness.py + license_guard.py 的体检结果填写
CANDIDATES = [
# (平台, 许可证, 闲置天数, 是否命中商业限制)
("TODO: 平台A", "TODO: 许可证", 0, False),
]
# ============================================================
def section(title):
return "\n## %s\n" % title
def build():
out = []
out.append("# %s 低代码平台选型结论\n" % PROJECT)
out.append("负责人:%s | 期望上线:%s | 成文日期:%s\n"
% (OWNER, DEADLINE, date.today().isoformat()))
out.append(section("一、结论"))
out.append("推荐路线:**%s**\n" % RECOMMENDED_ROUTE)
out.append("决定性理由:%s\n" % DECISIVE_REASON)
out.append(section("二、数据边界(第一否决项)"))
out.append("数据是否允许离开自有网络:**%s**\n"
% ("是" if DATA_MAY_LEAVE_NETWORK else "否"))
if not DATA_MAY_LEAVE_NETWORK:
out.append("以下载荷为业务必需且受监管,无法通过改提示词规避:\n")
for item in REGULATED_PAYLOAD:
out.append("- %s\n" % item)
out.append(section("三、成本测算"))
if CROSSOVER_MONTH:
out.append("自部署在第 %d 个月起总成本低于订阅方案。\n" % CROSSOVER_MONTH)
else:
out.append("测算区间内订阅方案始终更便宜,"
"**选择自部署的理由必须是合规或可控性,不能是省钱**。\n")
out.append("三年总成本:%s\n" % THREE_YEAR_COST)
out.append(section("四、锁定风险"))
out.append("锁定总分 %.1f(%s)。\n" % (LOCKIN_SCORE, LOCKIN_LEVEL))
out.append(section("五、候选平台体检"))
out.append("| 平台 | 许可证 | 闲置天数 | 商业限制 |\n")
out.append("|---|---|---|---|\n")
for name, lic, idle, blocked in CANDIDATES:
out.append("| %s | %s | %d | %s |\n"
% (name, lic, idle, "命中" if blocked else "无"))
out.append(section("六、复核约定"))
out.append("平台能力与条款会变。约定每季度用同一套脚本重跑一次体检,\n")
out.append("任一候选平台出现「闲置超 365 天」或「许可证变更」时重新评审。\n")
return "".join(out)
if __name__ == "__main__":
print(build())
报告的第六节「复核约定」容易被省掉,但它其实是最该保留的一节:平台能力与条款会变。约定每季度用同一套脚本重跑一次体检,任一候选出现「闲置超一年」或「许可证变更」时重新评审。选型不是一次性动作,是一项需要定期复查的决定。
06易错点:八个把选型做砸的典型姿势
每一条都对应一个真实会犯的错,以及它翻车时的样子
① 把「开源」直接当成「能商用」
错在哪:看见仓库里挂着熟悉的协议名就默认随便用。实际上不少平台是「标准协议 + 附加条款」,附加条款专门限制多租户运营、移除品牌标识这类商业化用法。
翻车的样子:产品做完准备对外卖,法务一看协议,多租户这条直接卡死,前面三个月白做。
怎么防:用 5.2 的闸门脚本先扫一遍,命中就去读 LICENSE 原文。接口返回 NOASSERTION 是最强的预警信号。
② 用托管版,却以为数据在自己手里
错在哪:同一个开源项目,官方托管版和自部署版界面一模一样,但数据流向完全相反。很多人用着人家的托管服务,却对外宣称「我们用的是开源方案,数据安全」。
翻车的样子:合规审计时被问「你们的病历数据存在哪」,答不上来。
怎么防:看你连的是谁的域名、数据落在谁的库里,别看界面长什么样。
③ 先算钱,再谈合规
错在哪:选型会一开场就在比单价。但合规是一票否决项,成本只是候选之间的排序依据。
翻车的样子:方案做完、预算批完,上线评审时被合规打回,从头再来。
怎么防:四问决策树的顺序不能改。成本永远排第四。
④ 把「脱敏一下就能用」当成解法
错在哪:以为调整提示词就能让数据不越界。但越界的是业务必需的载荷——知识库分片、数据库查询结果、历史会话,删掉就没法办事。
翻车的样子:脱敏脱到最后发现模型答不出东西,因为有用的信息全被脱掉了。
怎么防:跑 3.1 的审计脚本,看看必需载荷里还剩几项越界。剩一项就说明这条路走不通。
⑤ 低估运维人力,高估自建收益
错在哪:算自部署成本时只算机器钱,不算人的时间,因为「他本来就领工资」。
翻车的样子:TCO 表上自部署赢了,实际跑起来发现有人半个月扑在升级和排障上。
怎么防:把 OPS_MONTHLY 填成真实的人力分摊再算一遍。多数情况下交叉点会推后很远。
⑥ 拿「省钱」当自部署的理由
错在哪:本页 3.2 的实跑结果已经给出反例——在示例参数下,三年内订阅始终更便宜。自部署真正的价值是数据边界和可控性,不是账面成本。
翻车的样子:拿「省钱」去说服老板,半年后账一对,钱没省下来,还多了一个要人管的系统。
怎么防:先把交叉点算出来。算不出交叉点就别用成本做理由,换个诚实的理由——合规就是很好的理由。
⑦ 背界面操作,不学能力边界
错在哪:把「点哪个按钮」当成核心知识。平台半年改版两次,这些笔记三个月就过期。
翻车的样子:换了个平台就不会用了,因为从来没建立起「我需要一个能做 X 的功能」这种抽象。
怎么防:所有操作都用「找到 X 功能」来记。能力边界、数据流向、成本结构、退出成本,这四样才是不变量。
⑧ 相信「先用平台跑起来,以后再迁」
错在哪:迁移成本随时间指数上升。5.1 的实跑结果显示,一个跑了一年的中等项目锁定分已经落在「事实上换不动」的区间。
翻车的样子:一年后真要迁了,发现工作流编排结构、插件配置、会话历史、分发渠道全部带不走,等于重做。
怎么防:要迁就趁早。或者从第一天起就按 5.1 的三条建议做,把最贵的资产留在自己手里。
07自测题
点击题目展开答案;能把这 16 题说清楚,这一页就通了
低代码平台「低掉」的是哪部分代码?哪部分它替不了你?
低掉的是流程胶水:接收请求、调模型接口、解析返回、判断要不要调工具、回灌结果、流式输出、会话记录、错误重试。替不了你的是业务判断:提示词怎么写、知识库怎么切、什么情况下该调哪个工具。所以用了平台之后,效果好不好仍然取决于前面几讲的功底。
三条落地路线是哪三条?分界线是什么?
订阅在线平台、开源自部署、全自研框架。分界线是两个问题:谁持有你的数据、谁决定你能用什么。程序跑在谁的机器上、数据存在谁的库里,这两点一确定,路线就分清了。
「我们用的是开源方案,所以数据安全」——这句话错在哪?
混淆了托管版和自部署版。同一个开源项目,官方托管版和自己部署的版本界面一模一样,但数据流向完全相反。判断依据是:你连的是谁的域名、数据落在谁的库里,而不是界面长什么样。
为什么这一页不教「点哪个按钮」?
因为界面是最容易过期的部分,平台半年改版两次是常态。真正不变的是四样:能力边界、数据流向、成本结构、退出成本。所以操作一律记成「找到 X 功能」,建立的是「我需要一个能做 X 的功能,去这类平台里找它」的能力。
四问的顺序是什么?为什么成本排最后?
① 数据能否离开自有网络 → ② 有没有人长期承接运维 → ③ 需求是否超出编排表达能力 → ④ 量小且要得急吗。成本排最后是因为成本能谈,合规不能谈。把成本放第一位的选型,最后都会在上线评审时被打回重做。
哪一问是「一票否决」?为什么它不能靠改提示词绕过去?
第 1 问数据边界。因为越界的载荷里,用户问题、知识库分片、数据库查询结果、历史会话、上传文件这五项都是业务必需的,删掉就没法办事。可裁剪的只有内部接口地址和调试堆栈,而那两项本来就该裁。
一次平台调用实际会送出哪些东西?至少说出五项。
用户输入的原始问题、知识库命中的文档分片、业务数据库查询结果、历史多轮会话、用户上传的原始文件、内部系统的接口地址与字段名、调试用的完整堆栈。常见错觉是只想到第一项。
第 2 问的判断标准具体是什么?
出问题时,有没有一个明确的人会在当天响应。如果这个人不存在,或同时背着五个别的系统,自部署的实际形态会是:装好了、跑起来了、然后冻结在那个版本上,因为没人敢动。
怎么判断需求已经超出拖拽编排的表达能力?
看你是不是开始用一堆条件节点模拟 if-else 嵌套,或者不停往代码节点里塞逻辑。一旦画布变成「用鼠标写代码」,平台就从助力变成负担了,这时直接写代码更快也更好维护。编排擅长的是有向、分支有限、每步职责清晰的流程。
TCO 模型的核心是求绝对数字还是别的?
是找两条曲线的交点。绝对数字没有可比性(你的报价和我的不一样),有意义的是「第几个月起自部署开始更划算」。交叉点在 12 个月内说明量够大值得自建;在 36 个月之外说明订阅一直更便宜。
本页示例参数实跑的结论是什么?它推翻了哪个常见说法?
结论是三年内订阅方案始终更便宜,全自研更是差了一个数量级。它推翻的是「自建能省钱」。在这种量级下,选自部署的理由只能是合规与可控性。有人拿省钱说服你时,请他把交叉点算出来——多数情况下算不出来,因为交叉点在三年之外。
自部署成本里最容易被低估的是哪一项?为什么?
运维人力(OPS_MONTHLY)。因为它没走采购流程所以看不见,但一个人半天扑在升级上的成本,不会因为「他本来就领工资」而消失。把它显式写进模型,自部署的真实门槛才浮出水面。
哪些资产能带走、哪些带不走?规律是什么?
带得走:提示词文本、原始文档(难度 0.1)。带不走:已发布的分发渠道 0.9、会话历史 0.8、工作流编排结构 0.7、插件与工具调用配置 0.6、知识库分片与向量 0.5。规律是「内容」能带走,「结构」带不走——内容与平台无关,结构是平台私有格式。
降低锁定的三个做法是什么?
① 提示词与文档进自己的 git,平台里那份永远是副本;② 会话历史在调用时顺手写一份到自己的库,别等着导出;③ 分发走自己的域名,别把入口交给平台商店。办法不是不用平台,而是把最贵的三项攥在自己手里。
「开源」能推出「可以拿去卖」吗?附加条款通常卡什么?
不能。不少平台是「标准协议 + 附加条款」,附加条款常见限制三类用法:禁止多租户运营、不得移除品牌标识与版权信息、特定条件下需另行商业授权。这些对企业自用影响不大,但会直接否掉「改个皮对外卖」的方案。
GitHub 接口返回的许可证标识是 NOASSERTION,意味着什么?
说明自动识别没能匹配到标准许可证,几乎都意味着作者在标准协议上加了附加条款。这个信号比任何功能对比都重要——它意味着你必须去翻 LICENSE 原文,必要时找法务。关键词扫描只能筛出「需要人工读原文」的候选,不能替你做法律判断。
给开源平台做存活体检时,看 star 数还是看别的?
看最后一次提交距今多久。star 数只说明曾经火过。判读:≤30 天活跃,31–90 天正常,91–365 天放缓(选型时问清楚路线图),超过 365 天疑似停更(自建前先想好接盘成本)。并且要约定每季度重跑一次,选型不是一次性动作。
附术语表
这一页出现的概念,按选型讨论里被问到的频率排
| 术语 | 英文 / 写法 | 说明 |
|---|---|---|
| 低代码平台 | low-code platform | 把调用大模型的流程胶水换成可视化编排的工具。它替不掉提示词设计、知识库切分这些业务判断。 |
| 数据边界 | data boundary | 数据允许流动到的最远位置。选型里唯一的一票否决项,排在成本前面。 |
| 订阅在线平台 | hosted / SaaS | 程序跑在平台机器上、数据存在平台库里。起步最快,可控性最低。 |
| 开源自部署 | self-hosted | 拉开源项目到自己机器上跑,数据留在自有网络内。受许可证附加条款约束。 |
| 全自研框架 | self-built | 不依赖编排平台,直接用代码搭。自由度最高,门槛与斜率也最高。 |
| 托管版 vs 自部署版 | hosted vs self-hosted | 同一个开源项目的两种用法,界面一样但数据流向相反。判断依据是你连谁的域名、数据落谁的库。 |
| 总持有成本 | TCO | 不只是订阅费或机器费,要把运维人力显式算进去。它没走采购流程,但它是真金白银。 |
| 交叉点 | crossover point | 两条累计成本曲线相交的月份,也就是「从第几个月起另一条更划算」。TCO 测算真正要求的就是这个数,不是绝对金额。 |
| 平台锁定 | vendor lock-in | 换平台时带不走的那部分资产造成的迁移成本。规律是内容能带走、结构带不走。 |
| 锁定总分 | lock-in score | 各类资产的「规模 × 迁移难度」之和。<10 随时可换;10–30 可换但要留一个迭代周期;>30 事实上换不动。 |
| 许可证附加条款 | additional conditions | 挂在标准开源协议之后的自定义限制。常见三类:禁止多租户运营、不得移除品牌标识、特定条件需另行商业授权。 |
| NOASSERTION | SPDX 标识 | 自动识别未能匹配到标准许可证时返回的值,几乎等同于「这里有附加条款,请读原文」。 |
| 多租户 | multi-tenant | 用一套部署同时服务多个互相隔离的客户。这是最常被附加条款卡住的商业化用法。 |
| 存活体检 | liveness check | 用「最后一次提交距今多久」判断开源项目是否还有人维护。star 数只说明曾经火过,闲置天数才有信息量。 |
| 敏感级别 | public / internal / confidential / regulated | 数据分级。regulated 指受行业或法律强监管的数据,它出现在必需载荷里就意味着托管平台出局。 |
| 编排表达能力 | orchestration expressiveness | 可视化画布能表达的流程复杂度上限。判断越界的信号:开始用条件节点模拟 if-else 嵌套,或不停往代码节点塞逻辑。 |
| 复核约定 | re-evaluation cadence | 选型报告里最容易被省掉、也最该保留的一节。平台能力与条款会变,约定每季度重跑一次体检。 |