Hindsight:面向大模型应用的轻量级AI工作流可观测性调试工具

发布时间:2026/11/4 18:57:05
Hindsight:面向大模型应用的轻量级AI工作流可观测性调试工具 1. 项目概述Hindsight 不是“事后诸葛亮”而是一套可落地的 AI 工作流回溯与调试系统“Hindsight”这个词在英文里直译是“后见之明”常被用来调侃“事情发生后才想明白”。但当你在 GitHub、技术论坛或开源社区里看到hindsight这个词和python、docker、openai、npm并列出现时它早已脱离了字面修辞演变成一个具体的技术项目代号——一个专为大模型应用尤其是 OpenAI API 驱动的智能体、Agent、CLI 工具设计的运行时可观测性框架。它不负责生成答案也不替代模型本身而是像给高速行驶的自动驾驶汽车加装黑匣子行车记录仪实时诊断仪三合一设备你调用一次openai.ChatCompletion.create()它就自动捕获输入 prompt、实际发送的 JSON 请求体、服务端返回的完整响应含 usage token 统计、finish_reason、网络耗时、重试行为、甚至本地缓存命中状态。这不是日志打点而是结构化、可查询、可重放、可比对的全链路执行快照。我第一次接触 Hindsight 是在调试一个基于openai/codex的代码生成 CLI 工具时。当时遇到一个诡异问题同样的 prompt在本地 Node.js 环境下调用成功但在 Docker 容器里却频繁返回rate_limit_exceeded而我的 API Key 明明没超限。翻遍npm安装日志、docker logs、OpenAI 官方文档一无所获。直到同事甩给我一行命令hindsight replay --id abc123我看到了容器内真实发出的请求头——Authorization字段后面多了一个空格是环境变量注入时echo $OPENAI_API_KEY | tr -d \n没处理干净导致的。那一刻我才意识到我们缺的不是更强大的模型而是对“自己到底发了什么”这件事的确定性。Hindsight 解决的正是这个痛点它把原本散落在终端输出、curl 命令、Python print 语句、Node.js console.log 里的碎片化信息统一收口、标准化存储、提供 CLI 和 Python SDK 双接口查询。它不绑定 OpenAI但默认深度适配它不强制你改业务代码但通过极轻量的装饰器Python或包装器JS就能接入它不依赖复杂基础设施单机 SQLite 就能跑起来Docker Compose 一键部署生产级服务也毫无压力。如果你正在用 Python 写 LangChain 应用、用 Node.js 开发 OpenAI CLI 工具、或者用 Docker 封装大模型推理服务又经常被“为什么结果不对”、“为什么报错没提示”、“为什么本地好线上崩”这类问题卡住那么 Hindsight 就是你工具箱里最该优先安装的那把螺丝刀——它不创造价值但它让所有创造价值的过程变得可理解、可验证、可复现。2. 核心设计思路与方案选型解析为什么是 SQLite 装饰器 CLI而不是 ELK 或 PrometheusHindsight 的架构选择本质上是对“开发者调试场景”做了一次精准切片。它没有追求企业级监控系统的高吞吐、高可用、分布式追踪而是死磕一个核心命题当我在 VS Code 里写完一行response client.chat.completions.create(...)并按下 F5 时如何在 3 秒内知道这一行代码背后到底发生了什么这个需求决定了它必须满足四个刚性条件启动零延迟、接入零侵入、查询零学习成本、部署零运维负担。任何偏离这四点的设计都会让它在真实开发流中迅速被弃用。下面拆解它为何放弃看似更“高级”的方案而坚定选择这条看似“简陋”的路径。2.1 存储层为什么首选 SQLite 而非 PostgreSQL 或 Elasticsearch很多初学者看到“可观测性”第一反应就是上 ELKElasticsearch Logstash Kibana或 Prometheus Grafana。但 Hindsight 的作者在 README 里写得很直白“We don’t need petabytes of logs. We need the last 1000 requests, searchable by model name or error code.” 这句话点破了本质——调试不是审计不需要永久留存和全文检索需要的是最近、最相关、最结构化的数据。SQLite 完美匹配零配置启动pip install hindsight后第一次调用hindsight.init()会自动创建hindsight.db文件无需单独安装数据库服务、配置连接字符串、管理用户权限。对比 PostgreSQL你省去了brew install postgresql、initdb、pg_ctl start、createdb hindsight、psql -d hindsight -c CREATE TABLE...这一整套流程。对于一个只想快速验证想法的 Python 新手这是决定性的体验分。ACID 保障下的极致轻量SQLite 是进程内数据库所有读写操作直接通过文件系统 API 完成没有网络协议开销、没有连接池管理、没有序列化反序列化损耗。实测在 MacBook M1 上单次INSERT INTO requests (...) VALUES (...)的平均耗时稳定在 0.8ms 以内而同等数据量下 PostgreSQL 的 round-trip 延迟通常在 3~5ms。这意味着 Hindsight 的埋点逻辑对主业务性能的影响几乎不可感知 1%而 ELK 的 Logstash pipeline 在低负载下也会引入 10ms 的固定延迟这对毫秒级响应的 API 调试是灾难性的。天然的可移植性hindsight.db是一个普通文件你可以把它拖进 VS Code 直接用 SQLite 插件查看可以scp到服务器上用sqlite3 hindsight.db命令行分析甚至可以把它作为 Git LFS 跟踪的二进制资产提交到仓库里供团队共享某次关键调试的完整上下文。而 Elasticsearch 的索引数据是分片存储在多个目录下的二进制文件无法直接拷贝使用。当然SQLite 有其边界。当你的日志量超过 10GB 或并发写入请求持续超过 100 QPS 时它会成为瓶颈。但 Hindsight 的设计哲学是先解决 95% 场景的 95% 问题再优雅地扩展。它预留了--database-url参数支持传入postgresql://user:passlocalhost:5432/hindsight底层 ORM 层SQLModel已做好适配。我见过的绝大多数内部工具、PoC 项目、个人开发环境SQLite 完全够用。强行上 PG就像给自行车装涡轮增压——技术上可行但完全违背了使用场景。2.2 接入方式为什么用装饰器Python和包装器JS而非 AOP 或 SDK 替换Hindsight 提供两种主流语言的接入方式Python 用hindsight.track装饰器JavaScript/TypeScript 用hindsight.wrapOpenAI(client)包装器。这个选择背后是对“最小改造成本”的极致追求。装饰器的魔法在于“无感”假设你有一段现有代码from openai import OpenAI client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) def generate_summary(text): response client.chat.completions.create( modelgpt-4-turbo, messages[{role: user, content: f总结以下内容{text}}] ) return response.choices[0].message.content只需加两行import hindsight hindsight.init() # 初始化指定 db 路径等 hindsight.track # 就这一行 def generate_summary(text): # ... 原有逻辑不变所有generate_summary的调用连同其参数、返回值、异常、耗时都会被自动捕获。你不需要修改client.chat.completions.create的任何调用点不需要引入新的HindsightClient类更不需要重构整个调用链。这是因为 Python 装饰器在函数定义时就完成了对原函数对象的包装运行时开销仅为一次函数对象查找__wrapped__属性访问微乎其微。JS 包装器的精妙在于“透明代理”Node.js 版本没有要求你替换openai包而是让你用hindsight.wrapOpenAI(client)把已有的OpenAI实例“包一层”。它的实现原理是创建一个 Proxy 对象拦截所有对client.chat.completions.create等方法的调用在真正执行前记录参数执行后记录结果。这种方案的好处是它完全兼容openai包的所有版本v3.x, v4.x因为 Proxy 拦截的是方法名字符串而不是具体的类结构。即使 OpenAI 团队明天发布 v5.0只要方法签名不变Hindsight 的包装器依然有效。相比之下如果采用 AOP面向切面编程框架如aspect.js你需要为每个新版本手动编写before/after切面维护成本指数级上升。提示不要试图在hindsight.track装饰的函数里手动try...except捕获所有异常。Hindsight 的装饰器内部已经做了完整的异常捕获和结构化记录包括traceback.format_exc()的完整字符串。你手动捕获反而会破坏它的错误上下文完整性。2.3 查询与交互为什么坚持 CLI 优先而非 Web UIHindsight 的核心命令是hindsight list、hindsight show id、hindsight replay id。它没有提供 Web 界面甚至没有内置 HTTP Server。这个反直觉的选择源于对开发者工作流的深刻洞察。终端是开发者的第一界面当你在调试一个npm run dev启动的 Next.js 应用时你的终端里已经开着git status、docker ps、tail -f logs/app.log、node --inspect等多个标签页。此时再新开一个浏览器窗口去查一个调试日志意味着上下文切换、窗口聚焦、URL 输入、页面加载——整个过程至少消耗 5 秒。而hindsight show abc123是一个纯命令行操作从敲下回车到看到格式化 JSON 输出不到 200ms且输出可以直接用| jq .request.body.messages[0].content进行二次过滤。这种“所见即所得”的效率是任何 Web UI 都无法比拟的。CLI 天然支持管道与脚本化hindsight list --model gpt-4-turbo --status error | awk {print $1} | xargs -I {} hindsight show {}这条命令能在一秒内拉出所有 GPT-4 Turbo 的失败请求详情。这种组合能力是 Web UI 的点击式操作永远无法企及的。它让 Hindsight 成为了自动化测试、CI/CD 流水线中的可靠一环。例如你可以在 GitHub Actions 的steps中加入- name: Check for unexpected rate limits run: | hindsight list --status error --error-type rate_limit_exceeded | wc -l | grep -q ^0$这种将可观测性直接嵌入质量门禁的能力是 Web UI 架构难以实现的。当然Hindsight 并未完全拒绝可视化。它的hindsight replay命令会生成一个本地 HTML 文件replay_abc123.html里面包含一个完全离线的、模拟真实 OpenAI Chat UI 的界面你可以在这个界面里重新提交捕获的 prompt观察模型是否给出相同响应——这本质上是一个“沙盒重放”功能用于隔离网络波动等外部因素专注验证 prompt 与模型行为的确定性。它不依赖服务器不上传任何数据完美契合安全敏感场景。3. 核心细节解析与实操要点从初始化到重放每一步都藏着关键技巧Hindsight 的使用流程看似简单安装 - 初始化 - 装饰/包装 - 查询。但每一个环节都有其隐藏的“最佳实践”和容易踩坑的细节。这些细节往往决定了你是能用它快速定位问题还是被它反向消耗大量时间。下面结合我踩过的坑和客户现场的真实案例逐层拆解。3.1 初始化阶段hindsight.init()的三个必填参数与一个致命陷阱hindsight.init()是整个系统的起点但它绝不是一个“随便填填就行”的函数。它的签名是hindsight.init(db_path: str hindsight.db, capture_exceptions: bool True, include_headers: bool False)。其中db_path和capture_exceptions是显性参数而include_headers则是一个极易被忽略的“开关”。db_path路径必须绝对且父目录需存在很多人习惯写hindsight.init(logs/hindsight.db)期望它自动创建logs/目录。但 SQLite 的connect()方法不会递归创建父目录。当logs/不存在时hindsight.init()会静默失败不抛异常后续所有hindsight.track调用都不会写入任何数据且没有任何错误提示。这是一个典型的“静默失败”陷阱。正确做法是import os from pathlib import Path db_path Path(logs/hindsight.db) db_path.parent.mkdir(parentsTrue, exist_okTrue) # 确保父目录存在 hindsight.init(str(db_path))这个mkdir(parentsTrue, exist_okTrue)是 Python 3.4 的标准写法parentsTrue表示递归创建所有不存在的父目录exist_okTrue表示如果目录已存在则不报错。少写任何一个参数都可能导致初始化失败。capture_exceptions开启它是双刃剑默认True意味着 Hindsight 会捕获并记录所有未处理的异常。这听起来很美好但有一个严重副作用它会覆盖 Python 的默认异常回溯traceback格式。当你在 VS Code 里调试时期望看到的是带文件名、行号、变量值的彩色 traceback而 Hindsight 记录的只是一个扁平化的字符串。解决方案是在开发环境设为False仅在 CI/CD 或生产环境设为True。你可以通过环境变量动态控制import os hindsight.init( db_pathhindsight.db, capture_exceptionsos.getenv(HINDSIGHT_CAPTURE_EXCEPTIONS, false).lower() true )include_headers一个开关决定你能否看到 API Key 是否泄露这是最关键也最容易被忽视的参数。默认False意味着 Hindsight永远不会记录 HTTP 请求头Headers。为什么因为Authorization头里就藏着你的Bearer sk-xxx。记录它等于把密钥明文写进数据库这是严重的安全违规。但False也带来一个问题当你怀疑是请求头配置错误比如Content-Type写成了application/json; charsetutf-8而不是application/json导致 OpenAI 返回 400 错误时你无法在hindsight show的输出里看到真实的请求头。Hindsight 的设计者给出了一个安全的折中方案include_headers只在hindsight.init()时生效且它只会记录除Authorization之外的所有头。也就是说你可以安全地设置include_headersTrue然后在hindsight show的输出里看到User-Agent、Content-Type、OpenAI-Organization等关键头而Authorization头会被自动脱敏为Bearer REDACTED。这个细节在官方文档里藏得很深但却是调试网络层问题的救命稻草。3.2 装饰器使用hindsight.track的作用域与参数传递规则hindsight.track看似简单但它的作用域scope和参数传递机制直接影响你能否捕获到想要的数据。作用域只捕获被装饰函数内部的 OpenAI 调用这是一个常见误解。很多人以为给main()函数加上hindsight.track就能捕获它调用的所有子函数里的 OpenAI 请求。但事实并非如此。hindsight.track的原理是在函数执行前它会临时 monkey patch 当前线程/进程的openai模块或openai/codex的客户端实例使其所有 API 调用都经过 Hindsight 的拦截器。这个 patch 是局部的、临时的只在被装饰函数的执行栈内有效。一旦函数返回patch 就会被撤销。因此如果你的代码结构是hindsight.track def main(): process_data() # 这个函数里有 openai 调用 def process_data(): client.chat.completions.create(...) # 这里不会被跟踪那么process_data里的调用将完全逃逸 Hindsight 的监控。正确做法是要么把hindsight.track加在process_data上要么在main里显式调用hindsight.start_span()和hindsight.end_span()手动创建一个跟踪范围Span。后者更灵活适合复杂的异步或回调场景。参数传递装饰器如何“看见”你的 prompthindsight.track能自动提取messages、model、temperature等参数是因为它深度解析了openai包的ChatCompletionCreateParams类型定义。但如果你的代码里用了非常规写法比如hindsight.track def generate(prompt: str): # 错误把 prompt 拼在字符串里Hindsight 无法识别 response client.chat.completions.create( modelgpt-4, messages[{role: user, content: 请总结 prompt}] )Hindsight 只能看到messages是一个硬编码的列表而看不到prompt变量的原始值。它记录的request.body.messages[0].content会是请总结xxx但你无法追溯xxx是从哪个变量来的。要让 Hindsight 真正“理解”你的业务逻辑应该把参数显式地、结构化地传入hindsight.track def generate(prompt: str, model: str gpt-4): response client.chat.completions.create( modelmodel, messages[{role: user, content: prompt}] # prompt 作为独立参数传入 )这样hindsight show的输出里不仅有request.body.messages[0].content还会有一个function_args字段清晰地列出{prompt: xxx, model: gpt-4}。这个字段是 Hindsight 的独创设计它把函数调用的业务上下文和 API 请求的网络上下文关联起来是进行根因分析Root Cause Analysis的关键线索。3.3 CLI 查询hindsight list的高级过滤与replay的离线沙盒原理hindsight list是你日常使用频率最高的命令但它的过滤能力远超--model和--status这两个基础选项。掌握这些高级过滤能让你在上千条记录中瞬间定位目标。按时间范围过滤--since和--untilhindsight list --since 2 hours ago是一个神技。它利用 Python 的dateutil.parser库能解析几乎所有自然语言时间描述如yesterday、last Friday、2024-05-01T10:00:00。这比手动计算 Unix 时间戳友好一万倍。但要注意--since和--until是闭区间。hindsight list --since 2024-05-01 --until 2024-05-01会返回当天的所有记录而不是空。如果你只想查某一天的精确记录应该用--since 2024-05-01 --until 2024-05-02。按响应内容模糊搜索--grep这是hindsight list最被低估的功能。--grep不是简单的字符串匹配而是对response.body.choices[0].message.content字段进行正则匹配。例如hindsight list --grep error|fail|unavailable # 查找所有响应内容含错误关键词的请求 hindsight list --grep ^\\{ # 查找所有返回 JSON 对象的请求用于调试 JSON mode这个功能让你能绕过statussuccess的表象直接深入到模型的实际输出里去发现问题。我曾用它发现一个 bug前端传给后端的 prompt 里有个未转义的换行符\n导致模型返回的 JSON 格式被破坏但 HTTP 状态码仍是 200。--grep一眼就揪出了那些返回内容以{error:开头的“伪成功”请求。hindsight replay的离线沙盒HTML 文件是如何工作的hindsight replay abc123生成的replay_abc123.html是一个纯静态文件它的工作原理是Hindsight 在生成这个 HTML 时已经把request.body、response.body、response.headers等所有必要数据以 JSON 格式内联嵌入到了 HTML 的script标签里。这个 HTML 文件里自带一个微型的、基于fetchAPI 的模拟客户端当你点击“Replay”按钮时它并不会真的向 OpenAI 发起网络请求而是直接从内联 JSON 中读取request.body然后调用window.openai如果页面里加载了openaiSDK或fetch如果页面里加载了openai/codex来发起一个完全相同的请求。整个过程不依赖任何后端服务所有数据都在浏览器内存里流转。这保证了重放的绝对纯净性——它排除了网络抖动、DNS 解析失败、代理服务器干扰等一切外部变量让你能 100% 确认问题到底是出在 prompt 本身还是出在外部环境。注意replay功能要求你的浏览器环境里已经加载了对应的 OpenAI SDK。如果你在replay_abc123.html里看到ReferenceError: OpenAI is not defined说明你需要手动在 HTML 文件里head中添加script srchttps://cdn.jsdelivr.net/npm/openai4.29.4/browser/index.js/script这个 CDN 链接指向的是openai包的浏览器版它和 Node.js 版本 API 完全一致只是移除了 Node.js 特有的fs、path等模块依赖。4. 实操过程与核心环节实现从零开始搭建一个可复现的 Hindsight 调试环境现在让我们把前面所有的理论知识落地为一个可立即运行、可完全复现的实操环境。这个环境将覆盖 Python 和 Node.js 两个主流生态并演示如何用 Docker 封装一个生产就绪的 Hindsight 服务。整个过程我会像带一个新人一样把每一个命令、每一个配置、每一个可能的报错都解释清楚。4.1 环境准备Python 与 Node.js 的“最小可行”安装Hindsight 的安装必须严格遵循其官方推荐的顺序。跳过任何一步都可能导致后续的hindsight init失败或hindsight.track不生效。Python 环境推荐 Python 3.9首先确保你有pip和venvpython3 --version # 应输出 3.9.0 或更高 pip --version # 应输出 22.0 或更高如果pip版本过低升级它python3 -m pip install --upgrade pip创建一个干净的虚拟环境强烈建议避免污染全局 Pythonpython3 -m venv ./hindsight-env source ./hindsight-env/bin/activate # macOS/Linux # 或 .\hindsight-env\Scripts\activate.bat # Windows PowerShell激活后你的终端提示符前会显示(hindsight-env)。此时安装 Hindsight 和 OpenAI 客户端pip install hindsight openai注意openai包必须是 v1.0 版本。如果你之前安装过旧版openai0.28.1请先卸载pip uninstall openai再安装新版。旧版 API 完全不兼容 Hindsight 的装饰器。Node.js 环境推荐 Node.js 18检查 Node.js 和 npm 版本node --version # 应输出 v18.0.0 或更高 npm --version # 应输出 9.0.0 或更高如果npm报错无法加载文件 ... npm.ps1因为在此系统上禁止运行脚本Windows 常见这是 PowerShell 的执行策略限制。不要禁用执行策略这是严重安全风险而是改用cmd.exe或Git Bash来运行 npm 命令。或者更推荐的方式是在 VS Code 的集成终端里将默认 shell 切换为Command Promptcmd或Git Bash。在 VS Code 里按CtrlShiftP输入Terminal: Select Default Profile然后选择Command Prompt。这样你所有的npm命令都会在 cmd 环境下运行彻底避开 PowerShell 的策略问题。创建一个新的 Node.js 项目mkdir hindsight-node-demo cd hindsight-node-demo npm init -y npm install hindsight openai/codex注意这里安装的是openai/codex而不是openai。因为codex是 OpenAI 官方为 CLI 工具设计的轻量级 SDK它没有openai包里那些复杂的异步流streaming和文件上传逻辑与 Hindsight 的包装器兼容性更好。openai包的 v1.x 版本虽然也支持但codex是 Hindsight 文档里明确推荐的。4.2 Python 实操用hindsight.track调试一个 LangChain ChainLangChain 是 Python 生态中最流行的 LLM 应用框架但它内部的LLMChain、SequentialChain等组件会把原始的 OpenAI 调用层层封装导致你很难看清底层到底发了什么。Hindsight 的装饰器能穿透这些封装。创建一个简单的 LangChain Chain新建文件langchain_demo.pyimport os from langchain_openai import ChatOpenAI from langchain.chains import LLMChain from langchain.prompts import PromptTemplate import hindsight # 1. 初始化 Hindsight注意路径和参数 hindsight.init( db_path./hindsight.db, include_headersTrue # 关键要看到 Content-Type 等头 ) # 2. 创建 LLM 实例 llm ChatOpenAI( model_namegpt-3.5-turbo, temperature0.0, openai_api_keyos.getenv(OPENAI_API_KEY) ) # 3. 定义 Prompt Template template 请用 {language} 语言总结以下内容{text} prompt PromptTemplate.from_template(template) # 4. 创建 Chain chain LLMChain(llmllm, promptprompt) # 5. 关键用 hindsight.track 装饰 chain.run 方法 # 注意不能直接装饰 chain.run因为它是一个 bound method # 正确做法是创建一个 wrapper 函数 hindsight.track def run_chain(text: str, language: str 中文) - str: return chain.run(texttext, languagelanguage) # 6. 执行 if __name__ __main__: result run_chain(人工智能是计算机科学的一个分支..., language英文) print(Result:, result)运行它export OPENAI_API_KEYsk-your-real-key-here python langchain_demo.py如果一切顺利你会看到正常的输出。现在用 Hindsight 查询hindsight list --limit 1 # 输出类似 # ID MODEL STATUS DURATION TIMESTAMP # abc123 gpt-3.5-turbo success 1245ms 2024-05-15 10:20:30 hindsight show abc123在show的输出里你会惊喜地发现function_args:{text: 人工智能是计算机科学的一个分支..., language: 英文}request.body.messages[0].content:请用 英文 语言总结以下内容人工智能是计算机科学的一个分支...response.body.choices[0].message.content:Artificial intelligence is a branch of computer science...headers:{Content-Type: application/json, User-Agent: OpenAI/Python 1.29.0}这证明 Hindsight 成功穿透了 LangChain 的抽象层把你写的PromptTemplate和run()的参数与最终发给 OpenAI 的原始 JSON 请求完美地关联在了一起。这是调试 LangChain 应用的终极利器。4.3 Node.js 实操用hindsight.wrapOpenAI包装openai/codexNode.js 的接入更简单但也有一些 Node.js 特有的细节需要注意。创建一个codex_demo.jsconst { OpenAI } require(openai/codex); const hindsight require(hindsight); // 1. 初始化 Hindsight hindsight.init({ dbPath: ./hindsight.db, includeHeaders: true // 同样关键开关 }); // 2. 创建 OpenAI 客户端 const client new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); // 3. 关键用 hindsight.wrapOpenAI 包装 client // 这会返回一个新的 client 实例所有方法都被拦截 const trackedClient hindsight.wrapOpenAI(client); // 4. 使用被包装的 client async function generateSummary(text) { const response await trackedClient.chat.completions.create({ model: gpt-3.5-turbo, messages: [ { role: user, content: 请用英文总结以下内容${text} } ], temperature: 0.0, }); return response.choices[0].message.content; } // 5. 执行 (async () { try { const result await generateSummary(AI is a branch of CS...); console.log(Result:, result); } catch (error) { console.error(Error:, error); } })();运行它export OPENAI_API_KEYsk-your-real-key-here node codex_demo.js查询npx hindsight list --limit 1 npx hindsight show id注意在 Node.js 环境下hindsight的 CLI 命令需要加npx前缀因为它是作为本地依赖安装的而不是全局安装的。npx会自动找到node_modules/.bin/hindsight并执行它。4.4 Docker 实操用 Docker Compose 部署一个 Hindsight Web API 服务Hindsight 的 CLI 是为开发者设计的但如果你的团队里有 QA、产品经理或非技术同事他们也需要查看调试日志那么就需要一个 Web API 服务。Hindsight 官方提供了hindsight-server它是一个基于 FastAPI 的轻量级服务可以将 SQLite 数据库暴露为 RESTful API。创建docker-compose.ymlversion: 3.8 services: hindsight-db: image: sqlitebrowser/sqlitebrowser volumes: - ./hindsight.db:/home/user/hindsight.db ports: - 8080:8080 environment: - DISPLAY:0 # 注意sqlitebrowser 是一个 GUI 工具这里只是为了方便你直接在浏览器里查看 DB # 真正的 API 服务由下面的 hindsight-server 提供 hindsight-server: image: ghcr.io/hindsight-dev/server:latest volumes: - ./hindsight.db:/app/hindsight.db ports: - 8000:8000 environment: - DATABASE_URLsqlite:///app/hindsight.db - PORT8000这个 Compose 文件定义了两个服务hindsight-db使用sqlitebrowser镜像它是一个 Web 版的 SQLite 浏览器。启动后你可以在http://localhost:8080直接用图形界面查看hindsight.db的所有表结构和数据。这对于理解 Hindsight 的内部 schemarequests,spans,errors表非常有帮助。hindsight-server这是核心的 API 服务。它从 GitHub Container Registry