技术选型历程
一、项目背景与需要决策的问题
2026 年初,计划做一个个人记账理财助手。需求不复杂:能快速记录日常收支,能用自然语言查账。但就是这个"自然语言查账"的要求,把整个技术栈的复杂度拉高了。它意味着系统需要理解"这个月外卖花了多少钱"这种中文提问,翻译成 SQL,从数据库查出结果。
沿着这个需求往下拆,会碰到一连串的问题:
数据存哪?
交易记录有明确的用户、账户、分类关系,需要用关系型数据库吗?还是说 NoSQL 的灵活性更适合个人项目的快速迭代?
自然语言怎么转 SQL?
有现成的框架吗?还是得自己写?如果用自己的方案,是走规则匹配还是靠大模型生成?如果靠大模型,数据隐私怎么保障?
大模型的 prompt 怎么写?
数据库有十几张表,不可能全部塞进上下文窗口。怎么决定每次给模型看哪些表、哪些文档、哪些示例?
客户端怎么跟后端对齐?
用户登录后拿到的 token 存哪?每次请求怎么自动带上?后端做了上下文链路追踪,客户端怎么配合?
开发时数据从哪来?
数据库是空的,Text-to-SQL 没法调优,前端画图表也是白画。怎么生成看起来像真人的测试数据?
这些问题不是独立的——选了关系型数据库就得用 SQL 语法做 Text-to-SQL,选了 RAG 框架就涉及到怎么组织向量库、怎么检索上下文,Android 端的上下文传递又必须跟后端对齐。本文档就是这些决策过程的完整记录,但只写到"当时怎么想的、考虑了哪些选项",具体选了哪个由对应的专题文档给出。
二、决策一:用关系型数据库还是 NoSQL
2.1 这个问题是怎么来的
这是整个项目最早遇到的问题。记账数据看起来结构很清晰:用户、账户、交易、分类,彼此之间有关系。但 2026 年做个人项目,MongoDB 的吸引力是实实在在的——schema-less、快速原型、一个文档存整条交易记录不用 JOIN,听起来很适合小项目快速起步。
2.2 摆在面前的选择
走 NoSQL 路线(MongoDB 为代表)
优势是灵活。模型变了不用跑 migration,嵌套文档可以一次查出完整交易信息。劣势在于记账场景的 ACID 要求——转账操作需要原子性,MongoDB 的多文档事务虽然支持了,但性能开销和社区口碑是隐忧。另外,后续的 Text-to-SQL 方案都是输出标准 SQL,MongoDB 的 MQL 完全不在同一个生态里。
走关系型路线(PostgreSQL 或 MySQL)
优势是成熟。ACID 是几十年的积淀,JOIN 和窗口函数做财务分析非常顺手。但需要在项目初期就把 schema 设计好,改起来不如 NoSQL 灵活。PostgreSQL 和 MySQL 之间也有选择:前者 JSONB 和 pgvector 扩展更强,后者社区更广。
2.3 需要权衡的关键点
数据模型:记账数据本质上是关系型的还是文档型的?如果承认它是关系型的,强行套 NoSQL 会不会在后续的查询和分析中付出代价?
ACID vs 灵活性:个人记账对 ACID 的要求有多高?丢失一笔交易记录或者账不平是什么级别的灾难?灵活性的收益能否覆盖这个风险?
与 Text-to-SQL 的兼容:不管是选 Vanna、SQLCoder 还是 LangChain,它们都输出 SQL。如果选了 NoSQL,后面这条路就被堵死了。
向量检索:如果后续需要把 DDL 和文档做向量化检索,是单独搭一套向量数据库,还是用 PostgreSQL 的 pgvector 扩展复用现有数据库?
运维成本:个人项目能接受多少组件?一个 PostgreSQL 搞定存储+向量,还是 PostgreSQL + MongoDB + 向量数据库三件套?
2.4 当时纠结的地方
最纠结的其实是"万一后面发现关系型不够灵活怎么办"。但后来想清楚了:灵活和约束是 trade-off,对于财务数据来说,约束带来的安全性远大于灵活带来的便利。而且 PostgreSQL 的 JSONB 字段可以兜底一些"先存了再说"的场景。
具体选了什么、mysql 还是 pg,选的时候考虑了哪些额外因素,见专题文档。
三、决策二:怎么把自然语言翻译成 SQL
3.1 这个问题是怎么来的
数据库定下来之后(不论选了哪个),下一个问题就是:怎么让用户用中文提问,自动得到数据结果?这是整个项目的核心功能,也是技术含量最高的部分。
3.2 摆在面前的选择
当时市面上的 Text-to-SQL 方案大致分四类:
第一类:RAG 框架(Vanna.ai 为代表)
把 DDL、业务文档、示例 SQL 向量化存起来,用户提问时检索最相关的拼成 prompt,调 LLM 生成 SQL。优势是框架成熟、社区活跃、LLM 无关。劣势是检索策略的精度直接决定了 SQL 质量,需要在训练数据上花功夫。
第二类:专用微调模型(SQLCoder 为代表)
用 CodeLlama 或 StarCoder 微调出专门写 SQL 的模型,可以本地部署。优势是不依赖外部 API,劣势是没有内置 RAG 机制,每次要把完整 schema 塞进上下文。对于 15 张表的项目,token 消耗不小。
第三类:Agent 编排(LangChain SQL Agent 为代表)
LLM 通过工具调用去查表结构、执行 SQL、修正错误,灵活性最高。但每次查询需要多轮工具调用,延迟和 token 消耗都大,而且工具执行的数据结果会返回给 LLM——这在财务数据场景下需要仔细评估隐私风险。
第四类:端到端 Pipeline(Agentar-SQL 为代表)
意图理解、业务理解、数据理解全链路 pipeline,BIRD 榜单准确率最高。但部署复杂度高、社区生态还在建设中,对于个人项目来说可能是过度设计。
3.3 需要权衡的关键点
隐私与安全:如果走云端 LLM API,财务数据会经过第三方。有些方案只发 DDL 和 prompt,数据在服务端执行;有些方案会把查询结果也发给 LLM。这中间的差距有多大?
准确率:Text-to-SQL 的准确率不可能是 100%。生产环境中怎么兜底?用户看到错误的结果能不能修正?修正后能不能反哺模型?
成本:每个查询都调一次 LLM 的话,token 消耗是多少?一天 10 次查询、一天 100 次查询,费用分别是多少?有没有办法减少调用次数?
LLM 选型:选哪个大模型?DeepSeek、Qwen、GPT、本地模型?价格差多少?中文能力哪家强?SQL 生成能力哪家强?
3.4 当时纠结的地方
最纠结的是"框架 vs 自建"。框架开箱即用但可能不够灵活,自建灵活但工作量大。另一个纠结是隐私——个人财务数据走云端 API 始终是个心理门槛,不同方案在这方面的处理方式差别很大。
具体选了哪个框架、配哪个 LLM、为什么、以及在实践中碰到了什么问题,见专题文档。
四、决策三:怎么管理给 LLM 的上下文
4.1 这个问题是怎么来的
不论选了哪个 Text-to-SQL 方案,都会面临同一个问题:十几张表的 DDL、业务文档和示例 SQL 加起来远超 LLM 的上下文窗口(就算窗口够大,全量塞入的效果也不好——模型容易被不相关的表结构干扰)。
这个问题的本质是:在有限的上下文空间里,怎么只放最相关的信息?
4.2 摆在面前的选择
方案一:全量注入
所有 DDL、所有文档、所有示例全部拼进 prompt。实现最简单,但 token 消耗大,而且长上下文中的"迷失在中间"问题会导致准确率下降。
方案二:RAG 检索
向量化存储所有上下文,用户提问时检索最相关的拼装 prompt。优势是灵活,劣势是检索精度直接决定了 SQL 质量,而且 DDL、文档、示例混在一起检索可能会互相干扰。
方案三:分层检索
把检索拆成多步:先确定涉及哪些表,再确定需要哪些列和条件,最后匹配示例 SQL。每步缩小范围,最终拼装的 prompt 精确且精简。实现复杂度更高,但效果更好。
方案四:上下文压缩
用 LLM 或专用压缩模型把 DDL 和文档压缩成更短的表示。但压缩可能丢失关键信息(比如列注释里的业务语义),而且多一次 LLM 调用就多一份成本。
方案五:规则引擎降级
高频简单查询("本月花了多少""餐饮支出")不走 LLM,直接执行预置 SQL 模板。但这意味着需要持续维护模板,而且只能覆盖有限的问题类型。
4.3 需要权衡的关键点
检索精度 vs 覆盖率:分层检索精度高但可能遗漏信息,全量注入覆盖率 100% 但噪声大。怎么在两者之间找到平衡?能不能混合使用?
静态 vs 动态:DDL 基本上是静态的,但示例 SQL 会持续增长。动态增长的上下文怎么管理?需要定期重新训练向量库吗?
冷启动:项目初期没有用户反馈数据,示例 SQL 从哪里来?没有示例的时候怎么保证准确率?
规则的边界:规则模板能覆盖多少查询?覆盖率不够的时候用户会不会觉得"这个助手很蠢"?怎么判断一个查询是"走规则"还是"走 LLM"?
4.4 当时纠结的地方
这个问题是在 Text-to-SQL 框架跑起来之后才暴露的。第一版跑起来确实能查数据,但准确率不稳定——有时候查对了,有时候查错了,原因往往不是模型不行,而是给模型的上下文不对。所以需要单独花时间优化这一层。
具体采用了哪种策略组合、分层怎么分、token 预算怎么分配,见专题文档。
五、决策四:Android 端怎么安全传递上下文
5.1 这个问题是怎么来的
后端搭好之后,开始写 Android 客户端。后端的上下文链路已经设计好了——Middleware 从请求头里提取 user_id 和 request_id,存入 ContextVar,各层自动获取。客户端需要做的事情是:在每次请求里自动带上这些信息。
这引出两个子问题:
Token 存在哪?
用户登录后拿到 JWT,存在哪?SharedPreferences 明文存肯定不行。Android 的 EncryptedSharedPreferences 用 AES-256 加密,但每次读都要解密。放在内存里进程被杀就丢了。怎么做才安全又不影响性能?
每次请求怎么自动带上?
不能要求每个 API 调用都手动塞 Header。怎么让这个过程对上层业务代码透明?OkHttp 的 Interceptor 是最自然的方案,但 401 的处理、token 刷新的竞态条件、多个请求同时超时——这些 edge case 怎么处理?
5.2 需要权衡的关键点
安全 vs 便利:Token 存得越安全,读写就越麻烦。怎么让安全的方案在开发体验上也不差?
前后端约定:Header 的名称和格式(X-Request-ID、Authorization)需要前后端一致。这个约定应该由谁主导、什么时候定下来?
离线场景:没网的时候能不能看本地缓存的数据?如果能,缓存的鉴权怎么做?
多设备:未来如果支持多设备登录,Token 刷新和设备管理怎么处理?
5.3 当时纠结的地方
主要纠结在于"要不要做设备绑定"。从安全角度来说,设备绑定能防止 Token 被其他设备盗用;但从开发复杂度来说,涉及设备指纹采集、服务器端校验、多设备登录策略,工作量不小。对于个人项目来说值不值得一开始就做?
最终选择了什么方案、Token 怎么存、Interceptor 链怎么设计、竞态怎么处理,见专题文档。
六、决策五:开发过程中怎么获取测试数据
6.1 这个问题是怎么来的
这是一个"非技术"但很现实的问题。数据库搭好了,表建好了,API 写好了——里面一条数据都没有。Text-to-SQL 的 prompt 优化需要真实的查询场景来验证,前端图表需要数据才能渲染,演示给朋友看的时候,空数据库没有任何说服力。
6.2 摆在面前的选择
方案一:手工录入
自己每天记一两笔,攒几个月。最真实,但太慢了。而且很难覆盖"季度对比""年度趋势"这种需要大量数据的查询场景。
方案二:写脚本生成
用 Python 脚本生成一年的模拟交易数据写入数据库。快,但"看起来像真的"比"生成随机数"难得多。需要模拟消费规律——工作日和周末不一样、月底和省着花、固定日期发工资。
方案三:用开源数据集
网上有一些匿名的消费数据集,但 schema 不一定能对上自己的设计,而且数据可能不符合中文消费习惯。
6.3 需要权衡的关键点
真实性 vs 覆盖率:既要覆盖各种查询场景,又要让数据看起来像真人记的。怎么在随机性和规律性之间找平衡?
可复现:生成的数据需要可复现吗?如果每次跑了不一样,bug 是代码的问题还是数据的问题?
维护成本:生成脚本要不要跟着 schema 变?如果分类表改了字段,脚本要不要改?
6.4 当时纠结的地方
主要纠结在于"投入产出比"。写一个能生成"看起来真"的数据的脚本,可能需要几个小时。但这些时间花在别的地方会不会更有价值?后来想通了一件事:没有数据,所有选型都没法验证。这个工具的投入不是在做一个"边角料",而是在给前面的所有选型提供验证基础。
最终的脚本怎么设计的、模拟了哪些消费规律、怎么跟分类体系对齐,见专题文档。
七、决策之间的依赖关系
这五个决策不是并列的,它们之间有明确的依赖链条:
决策一(数据库选型)是最基础的决策。它不仅决定了数据的存储方式,还决定了 Text-to-SQL 的 SQL 方言、向量检索的实现方式(pgvector 还是独立向量库)、甚至 Android 端做数据缓存时的查询语法。
决策二(Text-to-SQL 引擎)建立在决策一之上。不管选了 PostgreSQL 还是 MySQL,SQL 的兼容性都需要考虑。而且决策二的输出(选了什么框架、配了什么 LLM)直接决定了决策三(上下文管理)的策略方向——不同框架的 RAG 机制不一样,上下文管理的优化空间也不一样。
决策三(上下文管理)是决策二的深化。框架选好之后,真正的调优工作才刚开始——怎么组织训练数据、怎么检索、怎么拼 prompt、怎么处理边界情况。这部分工作占了 Text-to-SQL 功能的大部分开发时间。
决策四(Android 端注入)与前三者相对独立,但需要跟后端的上下文链路对齐。后端的 Middleware 期望请求头里有什么字段,Android 端就得通过 Interceptor 注入什么字段。这是前后端协作的基础约定。
决策五(测试数据)看起来最独立,但实际上它是最能检验前面所有决策的环节。没有数据,Text-to-SQL 跑不起来、前端图表显示不了、性能没法测。它不是一个"顺便做做"的工具,而是开发和验证的基础设施。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)