跳到正文

llm-chat-server

面向电话对话的统一服务。它既提供基于 profile 的无状态流式 Chat,也提供与 Chat 节点完全独立的确定性 conversation strategy。

默认监听 9931,接口如下:

  • GET /health
  • GET /api/v1/chat/capabilities
  • POST /api/v1/chat/stream,以 SSE 返回 deltacompleteerror
  • GET /api/v1/conversation/capabilities
  • POST /api/v1/conversation,返回统一 JSON 结果

除健康检查外,配置了 server.authToken 时需发送 X-Callout-Internal-Token。 未注册的路径或错误 HTTP 方法不执行鉴权,统一返回 404{ "ok": false, "error": "接口不存在" }

Conversation strategy

策略注册表位于 src/conversation-registry.ts。当前注册 kb-mock,它不注册为 chat profile、不进入 Chat 节点、不保存会话状态,也不调用 Ollama 或 TTS。

初始化请求:

json
{ "strategy": "kb-mock", "action": "start", "sessionId": "call-uuid" }

响应中的固定话术为:

json
{
  "ok": true,
  "data": {
    "openingPrompt": "您好,请问有什么可以帮您?",
    "errorPrompt": "抱歉,系统暂时没有找到相关内容,请您换个说法再试试。"
  }
}

查询请求:

json
{ "strategy": "kb-mock", "action": "query", "sessionId": "call-uuid", "text": " 你好 " }

响应严格回显去除首尾空白后的用户原话,且不会主动挂机:

json
{ "ok": true, "data": { "answerText": "知识库模拟回答:你好", "hangup": false } }

非法 JSON、未知策略/action、空 sessionId 或空查询文本返回 HTTP 400;鉴权失败 返回 401。GET /api/v1/conversation/capabilities 只暴露策略 key、名称和说明。

运行

在仓库根目录运行:

bash
bun run dev:llm-chat

或进入本目录运行 bun run devbun run startbun run typecheckbun run buildbun run build:all

配置

开发态默认读取当前工作目录下的 config.json;独立可执行文件优先读取可执行文件同目录的 config.json。也可通过 LLM_CHAT_CONFIG_PATH 显式指定配置文件。

json
{
  "server": {
    "host": "0.0.0.0",
    "port": 9931,
    "authToken": ["chat-token"]
  },
  "llm": {
    "ollamaUrl": "http://127.0.0.1:11434/api/chat",
    "model": "qwen3.5:2b",
    "timeoutMs": 30000
  },
  "logging": {
    "dir": "logs",
    "level": "info",
    "maxSize": "20m",
    "maxFiles": "14d",
    "detailedContentEnabled": true
  }
}

环境变量优先于配置文件:

环境变量覆盖字段
LLM_CHAT_CONFIG_PATH配置文件路径
LLM_CHAT_HOST / LLM_CHAT_PORTserver.host / server.port
LLM_CHAT_AUTH_TOKENserver.authToken,支持逗号分隔多个 token
LLM_CHAT_OLLAMA_URL / LLM_CHAT_MODEL / LLM_CHAT_TIMEOUT_MSOllama 地址、模型与单轮总超时
LLM_CHAT_LOG_DIR / LLM_CHAT_LOG_LEVEL日志目录与级别
LLM_CHAT_LOG_MAX_SIZE / LLM_CHAT_LOG_MAX_FILES滚动文件大小与保留周期
LLM_CHAT_DETAILED_CONTENT_LOG_ENABLEDlogging.detailedContentEnabled;支持 true/false1/0yes/noon/off

日志

服务向控制台和 logs/application-YYYY-MM-DD.log 写入单行结构化日志,文件按日滚动。每个 POST /api/v1/chat/stream 都会生成内部 requestId,用于关联以下事件:

事件主要字段
requestrequestId、method、path、status、durationMs、profile、turn、messageCount、branchCount、finalEventType
ollama-requestrequestId、phase、model;详细模式增加完整 payload
ollama-responserequestId、phase、model、status、durationMs;回复生成阶段包含 usage,出口判断阶段包含 outcome / exitKey 摘要
ollama-errorrequestId、phase、model、status、durationMs、type、message;错误类型区分 timeoutclient-aborthttpnetworkparsevalidation

phasereply-generationexit-judgment。前者记录流式 Ollama NDJSON、拼接后的回复和 token 统计;后者记录原始响应 body、模型 content 与出口判断摘要。request.durationMs 覆盖完整 SSE 生命周期,finalEventType 标记最终的 completeerrorclient-abort;详细模式还记录请求 body 和最终 complete / error 数据。

默认开启详细内容日志(logging.detailedContentEnabled=true)。它会记录客户对话、服务端 system prompt、流程分支说明及模型输出,生产环境应根据隐私和数据保留要求评估;如不允许这些内容落盘,可设置:

bash
LLM_CHAT_DETAILED_CONTENT_LOG_ENABLED=false

关闭后不会记录 messages、prompt、客户话术、reply、原始响应或完整 payload,但仍保留关联 ID、阶段、模型、HTTP 状态、耗时、错误分类、usage 以及 outcome / exitKey 等排障摘要。任何模式都不记录请求头、鉴权 token 或 URL 查询参数。logger 或文件 transport 写入失败不会改变 SSE 输出和客户端取消逻辑。

本服务不收集 NLU 的 JSONL 微调数据;上述内容只进入常规滚动运行日志。

conversation 请求的摘要日志只记录 strategyaction。请求中的 sessionId、 用户文本和响应正文仅在 logging.detailedContentEnabled=true 时记录。

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。