先确认模型和检索工具都挂上——Iris 跑通第一条检索的检查点

文章导读
Iris 拿到手后,第一个要回答的问题通常不是“答得好不好”,而是“链路上每一环是不是真的接上了”。建议按进程、模型、检索工具、串联这四步依次验证:前一步没有可见信号,就先不要进入下一步。否则最后只得到一条空回答或一条没有引用的回答,很难判断问题卡在模型、索引还是串联逻辑上。
📋 目录
  1. 一 记录服务启动后暴露的端口与健康检查返回
  2. 二 确认模型客户端能返回一段固定文本
  3. 三 确认检索工具能被单独调用并返回候选片段
  4. 四 让模型基于检索结果作答并核对引用
  5. 五 把四步整理成一份可重复执行的检查顺序
A A

Iris 拿到手后,第一个要回答的问题通常不是“答得好不好”,而是“链路上每一环是不是真的接上了”。建议按进程、模型、检索工具、串联这四步依次验证:前一步没有可见信号,就先不要进入下一步。否则最后只得到一条空回答或一条没有引用的回答,很难判断问题卡在模型、索引还是串联逻辑上。

判断 Iris 是否跑通,先看四个可见信号是否齐全:健康检查返回 200 且响应体带明确的存活字段、模型对固定提示返回预期文本、检索工具单独调用能返回有结构的候选片段、最终回答里的引用能与原文逐句对应。四步中任意一步缺信号,建议先在原地修,不要跳到串联调试。端口、路由、字段名以实际部署的配置和日志为准,本文给的是检查顺序与通用骨架,不是某一版的固定接口。

记录服务启动后暴露的端口与健康检查返回

这一步只解决一个问题:进程是在运行,还是启动后打印几行日志就退出了。建议先用前台方式启动,让日志直接打到终端,不要一上来就丢到后台或交给进程管理器。

# 启动骨架,参数名以实际 CLI 为准
python -m iris.server `--config` ./configs/dev.yaml `--host` 0.0.0.0 `--port` 8000

启动日志里重点看三件事:实际监听的地址与端口、加载的配置文件路径、模型 provider 与检索后端各自初始化到哪一步。日志停在“loading config”或“connecting vector store”之后就退出,属于启动阶段失败,跟模型能力无关,先回去查配置和依赖服务。

# 健康检查请求
curl -i http://127.0.0.1:8000/healthz
  • 连接被拒或 curl 返回空,说明端口没有真正监听,回到启动日志找原因。
  • 返回 200 且响应体是 JSON、含明确的存活字段(如 status、version、message),可以进入下一步。
  • 返回 200 但响应体为空或只是一个静态字符串,说明健康检查只做保活、不检查下游依赖,后面几步要看得更细。
  • 健康检查路由不一定是 /healthz,可以先看 curl -s http://127.0.0.1:8000/openapi.json 里有没有 health 相关路径,或者直接查配置文件。

确认模型客户端能返回一段固定文本

把模型这一环先排除掉。方法是给一个不依赖检索、答案固定的提示,看返回内容是否稳定命中。提示里直接约束字数,便于肉眼判断是否被额外包装。

curl -s -X POST http://127.0.0.1:8000/v1/chat/completions \
  -H "Authorization: Bearer $IRIS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"default","messages":[{"role":"user","content":"只回复四个字:链路正常"}],"max_tokens":16,"temperature":0}'

观察返回体里 choices 的第一条内容是否就是“链路正常”,model 字段是否是预期的模型名,usage 里是否有 token 计数。有 token 计数通常说明请求确实打到了模型,而不是被本地兜底逻辑接住。

失败时要区分类型,不要都当成“模型挂了”:

  • 401 或 403:鉴权问题,检查 token、API Key、base_url 是否配套,最容易出现在换了环境但复用了旧配置的时候。
  • 408、504 或 curl 报 timeout:网络不通或上游超时,可以先确认出网、DNS 和超时配置。
  • 400:模型名或参数名不对,对照配置文件里的模型标识核对。
  • 200 但 content 为空:优先排查 max_tokens 是否设得过小,以及是否被内容策略拦截。

确认检索工具能被单独调用并返回候选片段

检索和模型必须分开验证。直接把检索结果塞进提示里混合调试,出了问题分不清是谁的错。先单独调用检索工具,输入一条语料里确实存在的查询。

curl -s -X POST http://127.0.0.1:8000/tools/retrieve \
  -H "Content-Type: application/json" \
  -d '{"query":"报销流程需要哪些材料","top_k":5}'

返回结构通常是一个数组,或 {"hits":[...]} 这类包装,每个候选片段一般包含:片段正文、来源标识(文件名、路径或 URL)、片段序号、相似度分数。字段名以实际部署为准,建议先原样 curl 一次看清 key 名,再写后面的断言或脚本。

先确认模型和检索工具都挂上——Iris 跑通第一条检索的检查点
  • 候选数量是否接近 top_k。明显偏少,通常是索引为空、只加载了部分文档,或过滤条件过严。
  • 片段正文字段是否有实际内容,不能全是空白或只有标题。
  • 来源标识能否定位到原始文件,后面核对引用要依赖这个字段。
  • 相似度分数是否随查询变化,固定不变说明可能在走缓存或假数据。

返回空数组时,先查索引构建日志和文档数量,不要先改相似度阈值。

让模型基于检索结果作答并核对引用

前三步都看到信号后,再发起一条完整的问答请求,问题要选答案明确写在语料里的那种,方便逐句核对。

curl -s -X POST http://127.0.0.1:8000/v1/chat \
  -H "Content-Type: application/json" \
  -d '{"session_id":"check-001","message":"报销流程需要哪些材料?","cite":true}'

返回体里除了回答正文,应当有引用列表。核对引用建议照这几条做,不靠“读着像”:

  1. 把引用片段里的关键句拿到原始文档里搜索,逐句能对上,而不是意思相近。
  2. 引用条目的来源和片段序号,应当能对应到上一步检索返回的同一批候选,而不是凭空生成的标识。
  3. 回答里出现的具体条目、材料名、办理环节,在引用片段中都能找到对应句子。
  4. 做一个反向对照:关闭引用开关,或临时清空检索返回,再问同样的问题。如果两种情况下回答几乎一致,说明引用只是装饰,模型并没有真正使用检索结果,需要回头检查拼装提示的那段逻辑。

把这一条问答的请求、返回原文、对应的检索候选一起留存,作为后续换环境时的对照基线。

把四步整理成一份可重复执行的检查顺序

换机器、升级版本、调整索引之后,按同一顺序复验,任何一步不通过就停在那一步,不要往下跑。下面这张表可以直接抄成自己的检查记录表。

步骤命令观察点通过标准
进程curl -i /healthz监听端口、配置路径、健康检查响应体返回 200 且响应体含存活字段,进程持续存活
模型最小 chat/completions 调用返回正文、model 名、usage正文命中固定文本,无 401/超时
检索工具POST /tools/retrieve候选数量、片段正文、来源标识、分数数量接近 top_k,正文非空且能定位原文件
串联POST /v1/chat 带 cite回答正文、引用列表、与检索候选的对应关系引用片段与原文逐句对应,关闭检索后回答发生变化

每次复验都建议保留四份材料:启动日志片段、模型调用返回 JSON、检索候选列表、带引用的问答记录。四份材料齐全,后面再出问题可以直接对比,判断是模型侧、索引侧还是串联侧的变化,而不是重新从头排查一遍。