文章目录一、背景一个被低估的 AI 落地场景二、技术架构不追新只求稳容器化部署三、核心流程两阶段流水线数据采集优雅降级策略AI 分析三条并行的 LLM 推理线四、几个值得一说的技术细节4.1 后端异步任务的双模式调度4.2 Token 黑名单的自动过期4.3 GSXT 反爬对策4.4 LLM 输出的鲁棒性处理五、为什么选 DeepSeek-V3 而不是 GPT-4六、教训与反思6.1 过早抽象 过度设计6.2 WeasyPrint 的 Windows 兼容性6.3 Redis 多 DB 的隔离策略6.4 对国内网络环境的适应七、写在最后一、背景一个被低估的 AI 落地场景不良资产处置是一个万亿级的市场。这个行业的起点和核心是尽职调查——你需要搞清楚每个债务人是否还有偿还能力、有没有隐匿资产、实际控制人是谁、有没有关联企业转移资产。传统的尽调流程是这样的手工打开 GSXT国家企业信用信息公示系统逐个搜索债务人名称逐页截图、记录股东、对外投资、行政处罚等信息打开裁判文书网查询涉诉记录把以上信息粘贴到 Word 里人工写分析结论一个批次的 30-50 个债务人一个项目经理要干 2-3 周这个流程有两个核心痛点信息搜集极其繁琐每个债务人有 5-10 个数据维度每个维度都需要在不同网站上查询、记录分析依赖经验判断关联关系、识别风险信号、评估回收价值高度依赖资深项目经理的个人经验观澜这个项目的目标很明确用 AI 自动化掉这个流程。二、技术架构不追新只求稳![系统架构]┌─────────────────────────────────────────────────────────────┐ │ Vue 3 TypeScript SPA │ │ Element Plus ECharts │ └──────────────────────┬──────────────────────────────────────┘ │ REST API ┌──────────────────────▼──────────────────────────────────────┐ │ FastAPI (Python) │ │ JWT Auth / SQLAlchemy / Pydantic v2 │ └──────┬───────────────────────────────────┬──────────────────┘ │ │ ┌──────▼──────┐ ┌───────▼──────────────────┐ │ MySQL 8 │ │ Celery Worker │ │ (业务数据) │ │ (异步任务流水线) │ └─────────────┘ └───────┬──────────────────┘ │ ┌──────────────┐ ┌───────▼──────────────────┐ │ Redis 7 │◄─────────────────┤ Dify LLM Orchestration │ │ (缓存/MQ) │ │ DeepSeek-V3 / Qwen-Max │ └──────────────┘ └──────────────────────────┘技术上我没有选择最时髦的方案而是做了务实的权衡层选型为什么前端Vue 3 Element Plus团队最熟表单/表格/对话框开箱即用后端FastAPIPython 异步生态最成熟的选择自动生成 OpenAPI 文档数据库MySQL 8.0业务数据 ACID 要求关系复杂没必要上 PG缓存/MQRedis 7同时做缓存和 Celery Broker减少运维组件异步任务Celery尽调是长时间运行的批处理任务必须异步LLM 编排Dify可视化编排 3 个并行的 LLM 节点降低 prompt 维护成本LLMDeepSeek-V3中文语义理解强性价比极高容器化部署全项目用 Docker Compose 编排了 6 个服务services:mysql# 业务数据库redis# 缓存 Celery Broker Session 存储backend# FastAPI 应用服务器backend-worker# Celery 异步工作节点frontend# Nginx 托管 Vue SPA没有上 k8s——项目初期一台机器 Docker Compose 足够。Elasticsearch 和 MinIO 排在了 P1等用户量上来再加。三、核心流程两阶段流水线整个尽调流程分为两个阶段由 Celery 编排上传债务人列表 (Excel/CSV) │ ▼ ┌───────────────────┐ │ 第一阶段数据采集 │ ← 串行执行带限速和反爬 │ GSXT 公开数据 │ │ Mock 降级 │ └─────────┬─────────┘ ▼ ┌───────────────────┐ │ 第二阶段AI 分析 │ ← Dify 工作流3 个 LLM 并 │ 关联关系穿透 │ 行执行 │ 风险识别与打标 │ │ 还款能力评估 │ └─────────┬─────────┘ ▼ ┌───────────────────┐ │ 报告生成 │ │ PDF (WeasyPrint) │ │ ZIP 批量打包 │ └───────────────────┘数据采集优雅降级策略GSXT 是核心数据源但它有严格的反爬机制。我们的策略不是死磕而是优雅降级流程 1. 查 Redis 缓存 (24h 过期) 2. 未命中 → 请求 GSXT 3. 请求成功 → 解析 HTML (三层降级解析) 4. 请求失败 (验证码/403/超时) → Mock 数据生成Mock 数据生成是一个有意思的设计——它不是随机造假而是确定性生成importhashlibdefgenerate_mock_data(company_name:str):seedhashlib.md5(company_name.encode()).hexdigest()random.seed(seed)# ... 用种子生成注册资本、涉诉数量、股东结构等# 同样的公司名始终得到同样的 Mock 数据这样保证了AI 分析管道永远有输入数据不会因为数据源不可用而中断测试时可复现按公司名就能得到确定的结果每个债权人都看起来像个真实企业AI 分析三条并行的 LLM 推理线在 Dify 工作流中三个 LLM 节点并行执行┌──────────────────────────┐ │ Hidden Relation │ │ Penetration │ │ DeepSeek-V3 temp0.3 │ │ 隐藏关联关系穿透 │ └──────────┬───────────────┘ │ 输入数据 ────────────────────┼─────────┬─────────┐ │ │ │ ┌──────────▼──┐ ┌──▼────────┐ │ │ Risk Tagging │ │ Repayment │ │ │ DeepSeek-V3 │ │ Capacity │ │ │ temp0.2 │ │ DeepSeek │ │ │ 风险标签 │ │ 还款能力 │ │ └──────────┬──┘ └──┬────────┘ │ │ │ │ └─────────┴─────────┘ │ ▼ ┌──────────────────┐ │ Jinja2 Merger │ │ 统一报告格式 │ └──────────────────┘1. 关联关系穿透温度 0.3分析股东树、人员交叉任职、投资链条识别隐形控制人、代持、循环担保。这是法律尽调中最耗脑力的部分。2. 风险语义理解与打标温度 0.2将企业经营状态、司法涉诉等数据转化为标准化的风险标签三级风险等级红/黄/绿覆盖 16 种风险类型。3. 还款能力评估温度 0.2多维度评估——经营状况、资产质量、负债水平、现金流、关联方支持、逃废债倾向输出回收等级高/中/低和预估回收金额区间。四、几个值得一说的技术细节4.1 后端异步任务的双模式调度Celery 在 Windows 开发环境下有个老问题——和 FastAPI 的事件循环冲突。我采取的策略是一个核心函数两种调度方式# 核心业务逻辑纯异步asyncdefrun_due_diligence_task(...):# ... 与事件循环无关的业务代码# Celery 包装生产环境celery_app.task(bindTrue,max_retries3)defprocess_due_diligence_task(self,...):asyncio.run(run_due_diligence_task(...))# 开发环境直接调用ifconfig.CELERY_TASK_ALWAYS_EAGER:asyncio.create_task(run_due_diligence_task(...))else:process_due_diligence_task.delay(...)通过CELERY_TASK_ALWAYS_EAGER这个开关开发时直接用create_task生产用 Celery 调度一套代码两套部署模式。4.2 Token 黑名单的自动过期JWT 登出后 token 仍然有效直到过期这是 JWT 的固有问题。通用的做法是维护一个黑名单但需要定时清理。用 Redis 的 TTL 特性这个问题的解法变得很优雅asyncdeflogout(token:str):# 解析 token 获取 jti 和剩余过期时间payloaddecode_token(token)jtipayload.get(jti)exppayload.get(exp)remainingexp-time.time()# 写入黑名单自动过期awaitredis.setex(ftoken_blacklist:{jti},remaining,1)不需要定时任务不需要手动清理Redis 在 TTL 归零后自动删 key。这个模式的寓意是——让基础设施为你做运维。4.3 GSXT 反爬对策如果说整个系统中有什么地方最像工程实践而非业务开发就是这个 GSXT 客户端的实现了8 个 User-Agent 轮换覆盖 Chrome/Firefox/Edge/SafariWindows/macOS 全平台请求抖动每次请求间隔0.8s ± 40%随机化Token 桶限速每分钟最多 20 次请求验证码检测响应体中关键词匹配命中则立即切换策略三层 HTML 解析回退dl/dt/dd结构 → 表格行解析 → 正则提取4.4 LLM 输出的鲁棒性处理LLM 的输出天然不稳定。我必须在生产环境中处理这些情况defsanitize_llm_output(raw_text:str)-dict:# 1. 替换 Python 布尔值textre.sub(r\bTrue\b,true,raw_text)textre.sub(r\bFalse\b,false,text)textre.sub(r\bNone\b,null,text)# 2. 剥离 Markdown 代码块标记textre.sub(r(?:json)?,,text)# 3. 尝试 JSON 解析try:returnjson.loads(text)exceptjson.JSONDecodeError:# 4. 实在解析失败返回原始文本return{raw_output:raw_text}核心原则LLM 会犯错pipeline 不能崩溃。无论 LLM 输出的质量如何管道都要能走完。质量问题是 AI 调优的事情系统可用性是工程的事情。五、为什么选 DeepSeek-V3 而不是 GPT-4这是一个经常被问到的问题。理由很简单中文语义理解在处理企业名称、法律文书、经营异常信息时DeepSeek 的中文语料覆盖远好于 GPT-4性价比价格大约是 GPT-4 的 1/20一次尽调任务可能要调用 50-100 次 LLM成本差距是数量级的数据合规金融行业的数据合规要求严格通过 Dify 可以灵活切换模型未来可以无缝迁移到私有化部署的 Qwen-Max效果足够在结构化分析和文本分类场景上DeepSeek-V3 与 GPT-4 的差距微乎其微六、教训与反思6.1 过早抽象 过度设计最初的 collector 模块我设计了一个完整的策略模式Strategy Pattern每种数据源一个实现类。最后发现——GSXT 占了 95% 的数据采集量其他数据源只有 5%。抽象了 6 个接口实际只用到 1 个。教训等你有第二个实现的时候再抽象。6.2 WeasyPrint 的 Windows 兼容性WeasyPrint 在 Linux 上运行良好但在 Windows 上需要 GTK3 运行时。这个坑在开发初期就发现了解决方式是惰性加载# 不在导入时加载在调用时加载defgenerate_pdf(...):fromweasyprintimportHTML# 延迟导入HTML(stringhtml).write_pdf(target)这样即使开发机上没有 GTK3FastAPI 也能正常启动不影响其他功能开发。6.3 Redis 多 DB 的隔离策略一个 Redis 实例承担了三个职责通过 DB 编号隔离DB用途策略0Celery Broker无需持久化1业务缓存 (GSXT 数据)24h TTL LRU2Token 黑名单按 TTL 自动过期没有引入额外的消息队列减少了运维复杂度。Redis 7 的单实例性能在这个量级上完全够用。6.4 对国内网络环境的适应Dify Plugin Daemon 的 Docker 镜像在 Docker Hub 上国内拉取经常超时。解决方案——注释掉用 Dify Cloud API 替代。这个决定是在第一次docker-compose up失败后 10 分钟做出的。在国内做开源基础设施开发先确认所有依赖能不能拉下来。七、写在最后“观澜这个项目目前还处于 MVP 阶段的尾声。从我的角度看这个项目的价值不在于技术有多新”而在于把一个非常传统的业务场景用 AI 重新做了一遍。不良资产行业的信息化程度整体偏低很多项目经理还在用 Excel 微信来管理尽调流程。AI 的落地机会不在于取代人而在于把专业人员的精力从信息搬运工中解放出来让他们专注于真正需要判断力的事情——比如怎么设计处置方案、怎么和债务人谈判。如果你对这个项目感兴趣或者你在做类似的 AI 传统行业落地的尝试欢迎交流。项目上线http://118.178.232.83