2026/9/15 14:27:48

TREK AI Booking Import:基于 LLM 的预订确认解析兜底方案详解

TREK AI Booking Import:基于 LLM 的预订确认解析兜底方案详解 TREK AI Booking Import基于 LLM 的预订确认解析兜底方案详解【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREKAI ParsingAI 解析是 TREK 自托管旅行规划器中一个可选附加组件addon它为常规的预订导入流程提供大语言模型LLM兜底当 KDE Itinerary 无法从预订确认邮件中提取结构化数据时——例如纯文本邮件、排版异常的 PDF、或供应商格式不被识别——TREK 会将文档交给 AI 模型生成可在保存前逐条审阅的预订记录。读完本文你将掌握 AI Parsing 的启用方式、三种提供商本地 Ollama / OpenAI 兼容 / Anthropic的选型与配置、管理员与用户两级配置的优先级规则以及它在源码层面先确定性解析、后 LLM 兜底的完整工作链路。管理员提示在 Admin-Addons 中启用AI Parsing位于Integration分组。预订导入本身仍然依赖kitinerary-extractor二进制参见 Reservations-and-Bookings 中关于导入按钮不可见时的处理方法。一、AI Parsing 与常规导入的关系兜底而非替代AI Parsing 不会取代 KDE Itinerary 的解析能力它只是其后备方案每个上传文件都先由 KDE Itinerary 解析只有 Itinerary返回空结果的文件才会被送往 AI 模型AI 生成的每条预订都会被标记为Review待审阅你可以在保存前或保存后确认其正确性。因此结构化票据如标准 PDF 机票、Apple Wallet 通行证依然走快速、确定性的常规解析路径AI 只介入那些常规解析会失败的文档。如果禁用该 addon导入行为与之前完全一致。从源码看这一三级模式逻辑在BookingImportService.preview中被明确实现见 booking-import.service.tsmode no-ai仅 KDE Itinerarymode fallback-on-empty仅当 Itinerary 返回空时才调用 LLM默认行为mode force-ai跳过 Itinerary所有文件都交给 LLM。前端在 BookingImportModal.tsx 中根据功能开关自动选择模式当服务器可用aiParsing功能时使用fallback-on-empty否则使用no-ai。每次解析后每个文件的 AI 使用情况aiAvailable/aiUsed都会记入文件报告且 LLM 来源的条目会被强制置为needs_review true。二、提供商选型本地优先云端备选该 addon 支持三种提供商提供商运行位置说明Local (Ollama)你自己的硬件预订数据不离开你的网络。隐私友好且推荐CPU 上即可运行。OpenAIOpenAI 的 API或通过自定义 Base URL 指向任意OpenAI 兼容端点需要 API key。AnthropicAnthropic 的 API需要 API key。原生读取 PDF——包括扫描件。关于扫描版 PDFLocal 和 OpenAI 兼容模型接收的是文档的提取文本。扫描版或纯图片 PDF 没有文本层因此这些提供商对其返回空结果。只有Anthropic能够摄取原始 PDF 并读取扫描件。这一差异在源码中有明确注释与实现llm-parse.service.ts 中仅 Anthropic 使用原生 PDF其 document block 可同时读取文本与扫描件OpenAI 兼容服务器含 Ollama/NuExtract无法摄取 PDF/file 部件因此其他所有提供商都使用提取文本。Anthropic 客户端将 PDF 以 base64document块发送anthropic.client.ts而 OpenAI 兼容客户端则通过{baseUrl}/chat/completions发送纯文本openai-compatible.client.ts其超时放宽至 300 秒以容纳本地 CPU 模型的冷加载与长文档首 token 延迟。文本提取与长度裁剪对非 Anthropic 提供商服务器会先做本地文本提取text-extract.ts.txt/.html/.htm/.eml直接按 UTF-8 解码HTML/XML 标签被剥离、空白被折叠.pdf通过pdf-parse提取内嵌文本层并清理-- N of M --页标记、折叠字母间距大写伪影如A M S T E R D A M→AMSTERDAM这些是 PDF 排版常见但会遮蔽预订字段的细节扫描版/纯图片 PDF 会得到空文本此时返回需要云端/视觉提供商的警告。提取的文本还会按提供商与内容做长度裁剪云端单次调用截取前 4000 字符本地模型若检测到航班号则放宽到 16000 字符长行程单否则 6000 字符单笔预订的关键信息通常集中在前部收紧上限能显著降低 CPU 上 prompt 预填充耗时。三、管理员实例级配置与本地模型管理启用 addon 后Admin-Addons 中其正下方会出现配置面板设置实例级配置适用于所有用户。留空则允许每个用户自行配置其提供商。Provider提供商— Local · OpenAI-compatible、OpenAI 或 Anthropic。Base URL— 除 Anthropic 外所有提供商均显示。本地 Ollama 服务器默认为http://localhost:11434/v1OpenAI 默认为https://api.openai.com/v1。可在此指向任意 OpenAI 兼容端点。API key— 本地服务器可选通常无需云端提供商必填。存储时加密保存后显示为掩码••••••••保持原值即保留已存密钥。Model— 模型 ID例如qwen3:8b、gpt-4o、claude-opus-4-8。如果你在此设置了提供商与模型将应用于所有用户并覆盖其个人设置。留空面板则让每个用户自带模型见下节。拉取本地模型选择Local提供商时面板可直接管理你的 Ollama 服务器Installed on the server服务器已安装列出 Ollama 已下载的模型带Refresh刷新按钮。点击某个模型即可选中。Pull a recommended model拉取推荐模型会下载模型并显示实时进度条。唯一推荐的模型是Qwen3 — 8Bqwen3:8b——CPU 上提取质量与速度最佳自动禁用思考· Apache-2.0。拉取完成后自动选中。你还可以选择服务器上已安装的任何其他模型或手动输入模型 ID。这段管理的后端实现是 llm-local.controller.ts 与 llm-local.service.ts前者暴露GET /api/admin/llm/local/models列出已安装模型10 秒超时与POST /api/admin/llm/local/pull将 Ollama 的 NDJSON 进度行以application/x-ndjson流式透传给前端渲染进度条后者会从 Base URL 剥离尾部/v1以推导 Ollama 管理 API 根地址/api/tags、/api/pull并校验协议必须为 http(s)。两个端点都只允许管理员访问JwtAuthGuardAdminGuard。密钥加密与 SSRF 防护API key 在入库前经maybe_encrypt_api_key加密返回给客户端前用MASKED_VALUE ••••••••掩码当客户端回传掩码哨兵值即用户未修改密钥时服务器会保留原有加密密钥llmConfig.ts。所有 LLM 出站请求都经safeFetchLlm发送ssrfGuard既允许 localhost/LAN 上的 Ollama又阻断 link-local 与云元数据地址段。四、用户级配置个人自带模型如果管理员将实例配置留空每个用户可在Settings → Integrations → AI parsing下配置自己的模型该分区仅在 addon 启用时出现使用你自己的 AI 模型从上传文件中提取预订。仅当管理员未为整个实例配置模型时生效。字段与管理员面板一一对应——提供商、模型、Base URL本地/OpenAI 使用、以及一个加密存储的 API key留空则保留当前密钥。此外还有一个Send documents as images将文档作为图片发送开关供支持视觉能力的模型使用。用户侧的实现对应 LlmConnectionSection.tsx其设置键定义在 settingsService.tsllm_provider取值限定local/openai/anthropic、llm_model、llm_base_url、llm_multimodal布尔开关、llm_api_key属于ENCRYPTED_SETTING_KEYS读取时经getDecryptedUserSetting解密。优先级管理员实例级模型永远优先。个人设置仅在未配置实例级模型时生效。这一优先级正是 llm-config.resolver.ts 的核心逻辑isAddonEnabled(ADDON_IDS.LLM_PARSING)未启用直接返回null否则先读addons表中的实例配置readInstanceConfig再回落至用户设置readUserConfig。这也是整个系统中唯一解密 API key 的位置。五、用 AI 导入预订的完整流程上传流程与常规预订导入完全相同——AI 只是在其背后运行在行程规划器中打开Reservations预订标签页点击Import from file从文件导入。将文件EML、PDF、PKPass、HTML、TXT——最多 5 个文件每个 10 MB拖入上传区域。上传对话框立即关闭右下角出现后台小部件background widget显示Parsing files…及实时计数。解析期间你可以继续浏览 TREK该部件在页面刷新后依然存活甚至会跟随你到其他页面。解析完成后点击部件上的Import按钮开始审阅。每条解析出的预订都会预填充到常规的预订或交通编辑器中逐一呈现。在你确认每条记录之前什么都不会保存。后台任务的实现细节上传对话框立即关闭 后台小部件持续跟踪的机制来自 import-jobs.service.ts控制器立即返回一个jobId解析在请求线程之外继续执行进度与完成事件通过broadcastToUser推送到用户的所有 WebSocket 连接可到达任意页面不限于行程房间。关键设计包括按用户串行执行每个用户维护一条任务链chainsMap新任务排队在前一任务之后——CPU 密集型推理同时只跑一个多文件自然排队而非并行结果保留 10 分钟JOB_TTL_MS 10 * 60_000完成后任务仍在内存中短暂保留供错过 WebSocket 推送的客户端通过 GET 补拉结果。保存时自动创建的内容模型被要求捕获完整预订——包括多段航班的每一段——保存时 TREK 会将各项内容接入行程booking-import.service.ts字段Fields— 预订/确认代码、日期时间以及按类型区分的座位、舱位、站台、总价与币种酒店附带地址租车附带公司餐厅与活动附带场所的电话和网站。地点Places— 酒店、餐厅、活动场所以及未附带地理坐标的交通站点会被地理编码并添加为行程地点地图 pin 随即出现。地点创建前会依次尝试名称地址→地址→名称三组 Nominatim 查询交通端点若缺坐标也会补地理编码但只有成功获得坐标的端点才会持久化到reservation_endpoints预览中的 From→To 不受影响。住宿Accommodations— 酒店预订会在匹配的入住/退房日期上创建住宿记录日期先精确匹配行程天数匹配不到则就近吸附到最近的一天确保住宿行一定能插入。关联费用Linked cost— 若启用了 Costs/Budget addon 且预订含价格会创建一条关联支出经freezeForeignRate冻结外币汇率避免结算后因实时汇率漂移重开账目未启用该 addon 时价格仅保留在预订上。源文档Source document— 上传文件被附加到该预订的文件中。每一条创建都会通过 WebSocket 广播reservation:created及accommodation:created、budget:created、place:created给所有在线成员实现实时协作同步。六、源码级原理提取路由器与确定性后处理对于本地Ollama提供商TREK 并不只是把文档丢给模型而是经过一个分层提取路由器extraction-router.ts——其设计目标为每个文档恰好一次模型调用单一语法强制调用Ollama 原生format语法约束若文本中检测到航班号detectFlightNumbers按序去重匹配[A-Z]{2}\d{2,4}模式则用扁平航班数组 schema一次调用提取所有航段——往返航班的去程与返程都在同一次调用中产出远比逐段调用快否则提取单条预订当关键词能确定类型时酒店/租车/火车/巴士/渡轮/餐厅/活动各有专属正则见 TYPE_KEYWORDS使用类型专属 schema无法确定时使用联合 schema 由模型自行选择类型缺省回退为 hotel。预订级字段确定性填充PNR/确认号、总价与币种不依赖模型推理而是用正则从原文中确定性抽取——文档自身的货币符号/代码被视为权威可纠正小型模型对¥误读为$的问题。航班到达日期同样被确定性推导到达时刻早于出发时刻即视为跨天隔夜航段日期1。结果经nuExtractToKiReservations映射为 schema.orgKiReservation节点进入与 KDE Itinerary 输出完全相同的下游 mapper 管线。针对小型 CPU 模型的健壮性处理还包括normalizeNode将小型模型摊平到根节点的类型专属字段折回reservationFor内层这正是 kitinerary mapper 读取的位置非 ISO 格式的自然语言日期如Aug 23 2025 13:30被统一重排为 ISO 8601小模型偶尔为找不到的价格输出空字符串也会被视为无价格。云端提供商OpenAI/Anthropic则走单次调用路径llm-prompt.ts 生成的系统提示词要求模型输出{ reservations: [...] }形式的 schema.org JSON-LD并明确要求提取文档中每一个航班/航段包括返程航段往返有两条或更多航班。Anthropic 通过强制 tool-useemit_reservations工具 tool_choice强制获得结构化输出OpenAI 兼容端优先请求json_schema对仅支持json_object的服务器DeepSeek、Mistral、部分 vLLM/llama.cpp自动重试降级且temperature固定为 0 以保证确定性。所有返回结果最后经共享的kiReservationSchema校验无法识别的输出会被跳过并记录警告而不会导致整次导入失败。这些行为均有对应测试验证见 extraction-router.test.ts 与 llm-parse.service.test.ts——例如隔夜航班日期滚动、德语总价Gesamtpreis 61,23 €→{price:61,23, currency:EUR}、文档币种覆盖模型猜测但保留模型已填价格、以及模型调用抛错时返回空列表加警告等边界情况。七、补充须知与注意事项无需新增环境变量也无需手动迁移——addon 完全在 UI 中配置实例配置存在addons.configJSON用户配置存在设置表llm_*键。本地推理可能较慢。纯 CPU 主机上单笔预订可能需要数十秒到一两分钟TREK 允许本地模型每份文档最长 5 分钟OpenAI 兼容客户端超时 300 秒。上传按用户逐个解析多个文件会排队而非并行。解析任务完成后约保留 10 分钟。请在此窗口内开始审阅。隐私— 使用 Local 提供商时任何数据都不会离开你的网络。使用 OpenAI 或 Anthropic 时文档文本或 Anthropic 场景下的 PDF 本身会被发送至该提供商进行提取。API 密钥绝不会以明文返回— 它们静态加密存储且始终以掩码显示。可用性探测/health/features端点返回{ bookingImport, aiParsing }两个布尔值client.ts前端据此决定是否显示 AI 相关 UIaiParsing为true的判定条件是 addon 已启用且能解析出有效配置llm-parse.service.ts。八、相关页面Reservations-and-Bookings — 本文所扩展的预订导入流程含支持格式、导入步骤、导入按钮不可见时的处理Admin-Addons — 启用 addon 的位置Budget-Tracking — 由导入预订创建的关联费用Transport: Flights, Trains, Cars — 交通类预订的字段与编辑方式【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREK创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考