@anydocs/ask为 anydocs 项目提供的本地问答服务。读取 pages/{lang}/*.json 和 navigation/{lang}.json,向 Reader 站点返回带完整面包屑引用的结构化答案。
0.3.1(2026-05-24)当前能力
- 索引、查询、HTTP 接口(SSE 流式
POST /v1/ask/stream+ 多轮 session round-trip)、Web 控制台、评测闭环(0.1.x)- β/γ 反馈回路 + Console Studio Feedback / Index / Traffic tab(0.2.0,RFC 0001 + 0002)
- 多轮对话默认开启(0.2.0,RFC 0003)
- Citation 语义校验全链路 + Studio verdict 展示(0.3.0,RFC 0005 alpha.2,默认 off)
- 嵌入式 Ask Widget MVP(0.3.0,RFC 0004 alpha.3,默认 off)
- A+ 失败查询诊断 CLI 链路
feedback diagnose(0.3.1,RFC 0006 alpha.2,默认 off)速览 ask 操作 / 原理 / 测评 / 优化方向:
docs/ask-overview.md。 产品背景见PRD.md,集成细节见ARCHITECTURE.md,版本历史见CHANGELOG.md。
全局安装:
npm install -g @anydocs/ask。如需开发本仓库或运行 fixtures,按下方源码模式走。
# 1. 克隆并安装依赖
git clone https://github.com/cregis-dev/anydocs-ask.git
cd anydocs-ask
pnpm install
# 2. 初始化工作区,生成凭证文件
pnpm dev workspace init
# 命令会在 ~/anydocs-ask-runtime/.env 写入凭证模板,编辑填入 API Key:
$EDITOR ~/anydocs-ask-runtime/.env
# 选 (A) 填 ANTHROPIC_API_KEY,或选 (B) 填 ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL
# 3. 启动 Web 控制台
pnpm dev console # 默认监听 http://127.0.0.1:4100
# 端口冲突?改用 4101–4199 范围外的端口(该范围保留给子进程):
pnpm dev console --port 4200
# 4. 验证服务就绪
curl http://127.0.0.1:4100/ # 应返回工作区首页 HTML
控制台启动后,在首页底部的 Add Project 表单中填入 fixtures/starter-docs 或你自己的 anydocs 项目路径,即可开始提问、运行评测、审阅 golden 集。
首次运行提示: BGE-M3 embedding 模型(约 600 MB)会在首次索引时自动下载到
~/.cache/huggingface/anydocs-ask/transformers/,视网速需 5–15 分钟;此后从本地缓存加载,预热约 5–10 秒。
不想用控制台?见 CLI 模式。
控制台是管理项目、调试查询、运行评测闭环的首选入口。仅绑定本地回环地址(127.0.0.1),自动按需启停各项目的子进程。
| URL | 内容 |
|---|---|
/ | 工作区首页——所有项目的状态与统计 |
/p/<name> | 项目页——启动/停止、Ask 体验台、Eval、Analyze、Golden Workshop |
/p/<name>/runs | 最近查询记录 |
/p/<name>/reports/<file> | 完整评测报告 |
添加项目 — 在首页填入项目路径(支持 ~ 展开),或通过 CLI 注册:
pnpm dev workspace add ./fixtures/starter-docs
pnpm dev workspace add /abs/path/to/my-docs --name my-docs
项目路径写入 projects.json 注册表,无需软链或移动源码目录。
启动 / 停止 — 在项目页点击按钮,或访问 /p/<name>?autostart=1。控制台会按需 spawn anydocs-ask serve 子进程,最多等待 30 秒完成预热。
空闲回收 — 超过 idleTimeoutMin(默认 15 分钟)无活动后,子进程自动退出释放内存。
重新索引 — 子进程运行期间,在项目页触发;内部调用 /v1/index/rebuild 完成。
项目页内嵌查询表单。请求默认带 dry_run=1 转发给子进程——答案正常展示,但不写入 runs 日志。勾选 Persist 后,本次交互以 source=console 写入 runs jsonl(默认不纳入分析和 golden 候选;需要时用 --include-console 显式开启)。
项目页提供三个评测闭环操作:
golden review + golden flush)。生成候选默认走 LLM 改写以提升查询质量,无凭据/调用失败时自动降级为模板原句;UI 实时流式展示每个 batch 的进度。生成候选耗时提示: Console 默认开启 LLM 改写。小项目(≤ 50 页)通常 30–90 秒完成(含网关偶发的 1–2 次重试),大项目按 50 条/批处理,整体随项目规模线性增长。需更快产出可在 CLI 用
--no-llm-rewrite跳过 LLM 步骤。
项目页加 Feedback / Traffic tab + Index tab 反向标注,把反馈数据消费成可行动信号(RFC 0002 T1–T4):
打开方式:在 anydocs.ask.json 设 feedback.enabled=true(写库 + 反馈先验上线)。详见 ARCHITECTURE.md §15。
控制台启动时读取 <workspace>/.console.json,缺省时全部使用默认值:
// ~/anydocs-ask-runtime/.console.json
{
"enabled": true, // 设为 false 可禁用控制台命令
"port": 4100, // 控制台端口,须在 4101–4199 之外
"idleTimeoutMin": 15, // 子进程空闲回收阈值(分钟)
"childPortRangeStart": 4101,
"childPortRangeEnd": 4199,
"childHealthTimeoutMs": 30000 // 等待子进程健康检查通过的超时(毫秒)
}
子进程端口从 [childPortRangeStart, childPortRangeEnd] 顺序分配,控制台自身的端口必须落在该范围之外。
Console 默认仍只监听 127.0.0.1。容器或反向代理部署需要监听非回环地址时,必须配置至少 16 位的管理员 Token,否则 Console 会拒绝启动:
export ANYDOCS_CONSOLE_HOST=0.0.0.0
export ANYDOCS_CONSOLE_AUTH_TOKEN='<random-token-at-least-16-characters>'
anydocs-ask console --workspace /runtime --port 4100
浏览器在 /login 输入 Token 后会获得 12 小时有效的 HttpOnly 签名会话 Cookie。Token 不会写入 Cookie;修改 Token 并重启 Console 会立即使旧会话失效。生产环境应始终经 HTTPS 反向代理访问。
单项目容器可通过 ANYDOCS_CONSOLE_ATTACHED_PROJECT 与 ANYDOCS_CONSOLE_ATTACHED_PORT 将 Console 附着到同一网络命名空间中已经运行的 Ask 服务,避免加载第二份 embedding 模型:
export ANYDOCS_CONSOLE_ATTACHED_PROJECT=docs
export ANYDOCS_CONSOLE_ATTACHED_PORT=3100
直接启动一个 HTTP 服务供 Reader 调用,不经过控制台:
# 启动服务(首次运行会自动初始化 ~/anydocs-ask-runtime/)
pnpm dev serve ./fixtures/starter-docs --port 3100
# 健康检查
curl http://localhost:3100/v1/health
# → {"status":"ok","warm":true,...}
# 提问
curl -X POST http://localhost:3100/v1/ask \
-H "Content-Type: application/json" \
-d '{"question":"鉴权怎么做?","lang":"zh"}'
<projectRoot> 的两种写法所有 CLI 子命令的第一个位置参数均为 <projectRoot>,指向一个 anydocs 项目目录(须包含 anydocs.config.json、pages/、navigation/)。支持两种形式,按是否含路径分隔符自动区分:
| 写法 | 示例 | 解析方式 | 适用场景 |
|---|---|---|---|
裸名称(不含 /) | my-docs | 从 projects.json 查找对应路径 | 已通过 workspace add 注册 |
| 文件系统路径 | ./fixtures/starter-docs、/abs/path | 按字面路径解析(相对路径基于 cwd) | 临时运行,无需注册 |
# 一次性注册
pnpm dev workspace add ./fixtures/starter-docs --name starter-docs
# 用裸名(已注册)
pnpm dev serve starter-docs --port 3100
pnpm dev eval starter-docs
# 用路径(无需注册)
pnpm dev serve ./fixtures/starter-docs --port 3100
pnpm dev serve /Users/me/work/product-docs
无论哪种写法,所有运行时数据(索引、runs、golden 集、报告)均写入 <workspace>/state/<projectId>/,源码仓库始终保持干净(双根分离,见 ARCH §16.1)。
POST /v1/ask
// 请求
{
"question": "如何鉴权?", // 必填,≤ 20,000 字
"lang": "zh", // 必填,"zh" | "en"
"context": { // 可选
"current_page_id": "auth", // 用户当前所在页面
"scope_id": "nav:zh.json:3" // 将检索范围限定到某个导航子树
}
}
// 正常响应
{
"type": "answer",
"answer_id": "ans_…",
"session_id": "sess_…", // 0.2+ multi-turn round-trip;client 回传同值即续聊
"answer_md": "…markdown…",
"answer_lang": "zh",
"citations": [
{
"citation_id": "cit_1",
"title": "鉴权",
"breadcrumb": […],
"url": "/zh/auth",
"snippet": "…"
}
],
"translation_notice": null // 跨语言降级时非 null
}
// 错误响应
{ "type": "error", "code": "invalid_question", "message": "…" }
POST /v1/ask/stream — 与 /v1/ask 同 body,返回 SSE token-by-token。事件类型:token / citations / answer / error。Reader 公网 UI 和 Widget chat-page 均走该端点。
POST /v1/ask/feedback — 提交 👍 / 👎 / 答错纠正(β 显式反馈)。需 feedback.enabled=true 才落 SQLite。
// 请求
{
"answer_id": "ans_…", // 必填
"rating": "up" | "down", // 必填
"comment": "答错了,应该是 …", // 可选,答错纠正文本
"session_id": "sess_…" // 可选,关联 multi-turn 会话
}
// 响应:{ "ok": true } 或 { "ok": false, "code": "...", "message": "..." }
GET /widget/v1.js + GET /widget/chat — 嵌入式 Widget 的 host bundle 与 iframe chat 页(RFC 0004)。需 widget.enabled=true 才挂;调用必须带 X-Project-Key header + origin 在 widget.allowedOrigins 白名单内,否则按 widget_disabled / invalid_project_key / origin_not_allowed / rate_limited 拒绝。
GET /v1/health — 预热完成后返回 {"status":"ok"},预热期间返回 {"status":"warming"};Reader 发起首次提问前应轮询此接口。
POST /mcp — MCP 知识库接口(RFC 0007),把本项目文档暴露成可被 Claude Code / Cursor 等 agent 调用的 MCP server,走 Streamable HTTP 无状态传输。默认关闭,需在 anydocs.ask.json 开 mcp.enabled=true。三个 tool:
| tool | 作用 | 成本 |
|---|---|---|
search | 混合检索,返回相关片段 + 来源页 + URL + breadcrumb | 无 LLM(只开此 tool 可不配 API Key) |
ask | 合成答案 + 校验过的 citations | 消耗服务端 LLM |
fetch_page | 按 page_id 取整页原文 | 无 LLM |
// anydocs.ask.json
{
"mcp": {
"enabled": true,
"tools": ["search", "ask"], // 想省 LLM 成本可只留 ["search"]
"rateLimitPerMinute": 60,
"allowedOrigins": [] // 浏览器型客户端的 Origin 白名单(server-to-server 留空)
}
}
独立的 Intent Router 只处理需要上下文消解或语义压缩的问题。无历史的短问题,以及 带明确 API 路径、错误码或异常名的诊断输入,会直接走确定性快路径,避免回答前再调用 一次大模型;其余路由结果按“问题 + 最近三轮历史”做进程内 TTL 缓存。长日志仍会先 脱敏,本地提取器保留接口路径、错误码、字段名和首尾空格等原始线索。密钥、Token、 签名和密码不会发送给 Router、Embedding 或回答模型,也不会以明文写入 Traffic 日志。
鉴权用 bearer token,走环境变量 ANYDOCS_MCP_TOKEN(密钥不入配置文件);设置后调用须带 Authorization: Bearer <token>,否则 401。未设置则端点开放——仅适合 loopback / 可信内网(此时端口无关的 DNS-rebinding Host 守卫生效)。在 MCP 客户端里注册(以 Claude Code 为例):
claude mcp add --transport http anydocs-ask http://127.0.0.1:3100/mcp \
--header "Authorization: Bearer $ANYDOCS_MCP_TOKEN"
全局安装(
npm install -g @anydocs/ask)后anydocs-ask <cmd>直接可用。从源码运行时,把下方所有anydocs-ask <cmd>换成pnpm dev <cmd>(仓库根目录),或pnpm build后用node dist/cli.js <cmd>。
# 服务
anydocs-ask serve <projectRoot> [--port 3100] [--host 127.0.0.1]
anydocs-ask reindex <projectRoot>
anydocs-ask status <projectRoot>
# 工作区管理(默认路径 ~/anydocs-ask-runtime/,可用 --workspace 或 $ANYDOCS_ASK_WORKSPACE 覆盖)
anydocs-ask workspace init
anydocs-ask workspace ls
anydocs-ask workspace add <path> [--name <name>] # 注册到 projects.json
anydocs-ask workspace rm <name> # 移除注册(保留 state 数据)
# 查询记录(每次 /v1/ask 追加一行;ARCH §16.4)
anydocs-ask runs tail <projectRoot> [--n 50]
anydocs-ask runs export <projectRoot> --since <when> [--format jsonl|csv]
# 评测闭环(ARCH §16.3 / §16.5 / §16.6)
anydocs-ask golden generate <projectRoot> [--from structure|runs] [--limit N]
[--since 14d] [--no-llm-rewrite] [--force]
anydocs-ask golden review <projectRoot> [--reviewer <name>]
anydocs-ask golden import <projectRoot> --file <jsonl> [--replace]
anydocs-ask eval <projectRoot> [--baseline <path>]
anydocs-ask analyze runs <projectRoot> [--since 7d]
# 反馈闭环(0.2+,RFC 0001 / 0006;详见 ARCH §15)
anydocs-ask feedback status <projectRoot> # 计数 β/γ 行 + 反馈先验状态
anydocs-ask feedback export <projectRoot> # SQLite → inbox/*.md,git 友好
anydocs-ask feedback import <projectRoot> # 审过 inbox/*.md → approved.jsonl
anydocs-ask feedback diagnose <projectRoot> # RFC 0006 A+ 失败查询聚类 → suggestions/cluster_*.md
[--threshold N] # 反馈数量下限(默认 aplus.threshold=50)
[--observation-window 28d] # 时间窗(默认 aplus.observationWindow)
[--shadow] # 强制写到 suggestions/.shadow/ 子目录
[--dry-run] # 跑全流程不写盘
golden import is intended for source-controlled, hand-curated eval sets.
Relative --file paths are resolved from <projectRoot>, then written into
the runtime workspace under <workspace>/state/<projectId>/golden/cases.jsonl.
--since 接受 ISO 日期(2026-04-01)、ISO 时间戳,或时长简写(7d / 48h / 30m)。
anydocs.ask.json(可选)在 <projectRoot> 放置 anydocs.ask.json 可覆盖默认配置(模型、检索权重、CORS 域名等),所有字段均为可选。完整字段列表见 ARCHITECTURE.md §9。
项目也可以追加自定义 Prompt 说明,用于按文档站的业务语境特调回答风格;核心的“只基于片段回答 / 必须引用 / 不编造”规则不会被覆盖。也可在 Web Console 的项目页 Prompt settings 里编辑。为避免 prompt 过大,保存时会把换行/多空格压成单空格,并限制 assistantName 最多 80 字符、systemInstructions 最多 20 条、每条最多 500 字符。
{
"prompt": {
"assistantName": "Cregis AI 助手",
"systemInstructions": [
"Payment Engine 主要用于订单、收款、托管收银台、支付回调和订单状态查询。",
"WaaS 主要用于钱包、地址、充值、归集、提币和链上资产管理。",
"回答时先给直接结论,再给必要步骤或注意事项。"
]
}
}
按 RFC 引入顺序列;所有段默认 整段 off,flip enabled 后才生效。完整字段语义与默认值见 ARCHITECTURE.md §9。
{
// Intent Router(默认 ON);model=null 时复用主回答模型
"router": {
"enabled": true,
"model": null, // 可填网关支持的更小、更快模型
"fastPathMaxChars": 240, // 0 = 关闭确定性快路径
"cacheTtlMs": 300000,
"cacheMaxEntries": 512
},
// RFC 0001 §3 — β 显式 + γ 隐式反馈通道(写库 + reranker 先验)
"feedback": {
"enabled": false, // 整段开关
"implicitSignals": "session-only", // γ 信号范围
"rerankerWeight": 0.15 // 反馈先验进 §6 步骤 4 的权重
},
// RFC 0003 — 多轮对话(默认 ON,0.2.0 起 design partner 自然多轮可用)
"multiTurn": {
"enabled": true,
"historyTurns": 3 // history 拼进 prompt 的最近轮数 [1, 20]
},
// RFC 0005 — citation 语义校验(异步 fire-and-forget,复用主 LLM)
"citationSemanticCheck": {
"enabled": false,
"mode": "shadow" // "shadow" | "enforce"(0.4 H1 升级才接通 enforce)
},
// RFC 0004 — 嵌入式 Ask Widget(host bundle + iframe chat)
"widget": {
"enabled": false,
"rateLimitPerMinute": 60, // per (project_key, origin) token bucket
"allowedOrigins": [] // 白名单 origin,空数组 = 一律拒
},
// RFC 0006 — A+ 失败查询诊断(聚类 + 建议生成)
"aplus": {
"enabled": false, // 0.4.0 GA 由 operator flip
"threshold": 50, // 反馈数量产品门槛
"observationWindow": "28d", // 4 周观察窗
"embedSimilarityThreshold": 0.65 // bge-m3 cosine 聚类阈值
},
// RFC 0007 — MCP 知识库接口(POST /mcp,Streamable HTTP 无状态)
"mcp": {
"enabled": false,
"tools": ["search", "ask"], // search(无LLM) / ask(耗LLM) / fetch_page
"rateLimitPerMinute": 60, // per (token|origin) token bucket
"allowedOrigins": [] // 浏览器型客户端的 Origin 白名单
// 鉴权 token 走 env ANYDOCS_MCP_TOKEN,不入此文件
}
}
面向公开发布的开发者文档与产品手册,为终端用户提供精准问答。每个进程对应一个 anydocs 项目,多项目通过多端口独立部署。多语言是一等公民,当前支持 zh / en,同语言优先,跨语言时自动翻译降级(详见 PRD §4.8)。
pnpm install
pnpm dev serve ./fixtures/starter-docs # 直接运行源码(--experimental-strip-types)
pnpm dev console # 启动 Web 控制台
pnpm test # node --test
pnpm typecheck
pnpm build # 输出到 dist/
依赖:Node ≥ 20,pnpm ≥ 8。实现进度与变更历史见 CHANGELOG.md。
MIT
165 commits
55 commits
TypeScript
96.1%
CSS
3.4%
@anydocs/ask为 anydocs 项目提供的本地问答服务。读取 pages/{lang}/*.json 和 navigation/{lang}.json,向 Reader 站点返回带完整面包屑引用的结构化答案。
0.3.1(2026-05-24)当前能力
- 索引、查询、HTTP 接口(SSE 流式
POST /v1/ask/stream+ 多轮 session round-trip)、Web 控制台、评测闭环(0.1.x)- β/γ 反馈回路 + Console Studio Feedback / Index / Traffic tab(0.2.0,RFC 0001 + 0002)
- 多轮对话默认开启(0.2.0,RFC 0003)
- Citation 语义校验全链路 + Studio verdict 展示(0.3.0,RFC 0005 alpha.2,默认 off)
- 嵌入式 Ask Widget MVP(0.3.0,RFC 0004 alpha.3,默认 off)
- A+ 失败查询诊断 CLI 链路
feedback diagnose(0.3.1,RFC 0006 alpha.2,默认 off)速览 ask 操作 / 原理 / 测评 / 优化方向:
docs/ask-overview.md。 产品背景见PRD.md,集成细节见ARCHITECTURE.md,版本历史见CHANGELOG.md。
全局安装:
npm install -g @anydocs/ask。如需开发本仓库或运行 fixtures,按下方源码模式走。
# 1. 克隆并安装依赖
git clone https://github.com/cregis-dev/anydocs-ask.git
cd anydocs-ask
pnpm install
# 2. 初始化工作区,生成凭证文件
pnpm dev workspace init
# 命令会在 ~/anydocs-ask-runtime/.env 写入凭证模板,编辑填入 API Key:
$EDITOR ~/anydocs-ask-runtime/.env
# 选 (A) 填 ANTHROPIC_API_KEY,或选 (B) 填 ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL
# 3. 启动 Web 控制台
pnpm dev console # 默认监听 http://127.0.0.1:4100
# 端口冲突?改用 4101–4199 范围外的端口(该范围保留给子进程):
pnpm dev console --port 4200
# 4. 验证服务就绪
curl http://127.0.0.1:4100/ # 应返回工作区首页 HTML
控制台启动后,在首页底部的 Add Project 表单中填入 fixtures/starter-docs 或你自己的 anydocs 项目路径,即可开始提问、运行评测、审阅 golden 集。
首次运行提示: BGE-M3 embedding 模型(约 600 MB)会在首次索引时自动下载到
~/.cache/huggingface/anydocs-ask/transformers/,视网速需 5–15 分钟;此后从本地缓存加载,预热约 5–10 秒。
不想用控制台?见 CLI 模式。
控制台是管理项目、调试查询、运行评测闭环的首选入口。仅绑定本地回环地址(127.0.0.1),自动按需启停各项目的子进程。
| URL | 内容 |
|---|---|
/ | 工作区首页——所有项目的状态与统计 |
/p/<name> | 项目页——启动/停止、Ask 体验台、Eval、Analyze、Golden Workshop |
/p/<name>/runs | 最近查询记录 |
/p/<name>/reports/<file> | 完整评测报告 |
添加项目 — 在首页填入项目路径(支持 ~ 展开),或通过 CLI 注册:
pnpm dev workspace add ./fixtures/starter-docs
pnpm dev workspace add /abs/path/to/my-docs --name my-docs
项目路径写入 projects.json 注册表,无需软链或移动源码目录。
启动 / 停止 — 在项目页点击按钮,或访问 /p/<name>?autostart=1。控制台会按需 spawn anydocs-ask serve 子进程,最多等待 30 秒完成预热。
空闲回收 — 超过 idleTimeoutMin(默认 15 分钟)无活动后,子进程自动退出释放内存。
重新索引 — 子进程运行期间,在项目页触发;内部调用 /v1/index/rebuild 完成。
项目页内嵌查询表单。请求默认带 dry_run=1 转发给子进程——答案正常展示,但不写入 runs 日志。勾选 Persist 后,本次交互以 source=console 写入 runs jsonl(默认不纳入分析和 golden 候选;需要时用 --include-console 显式开启)。
项目页提供三个评测闭环操作:
golden review + golden flush)。生成候选默认走 LLM 改写以提升查询质量,无凭据/调用失败时自动降级为模板原句;UI 实时流式展示每个 batch 的进度。生成候选耗时提示: Console 默认开启 LLM 改写。小项目(≤ 50 页)通常 30–90 秒完成(含网关偶发的 1–2 次重试),大项目按 50 条/批处理,整体随项目规模线性增长。需更快产出可在 CLI 用
--no-llm-rewrite跳过 LLM 步骤。
项目页加 Feedback / Traffic tab + Index tab 反向标注,把反馈数据消费成可行动信号(RFC 0002 T1–T4):
打开方式:在 anydocs.ask.json 设 feedback.enabled=true(写库 + 反馈先验上线)。详见 ARCHITECTURE.md §15。
控制台启动时读取 <workspace>/.console.json,缺省时全部使用默认值:
// ~/anydocs-ask-runtime/.console.json
{
"enabled": true, // 设为 false 可禁用控制台命令
"port": 4100, // 控制台端口,须在 4101–4199 之外
"idleTimeoutMin": 15, // 子进程空闲回收阈值(分钟)
"childPortRangeStart": 4101,
"childPortRangeEnd": 4199,
"childHealthTimeoutMs": 30000 // 等待子进程健康检查通过的超时(毫秒)
}
子进程端口从 [childPortRangeStart, childPortRangeEnd] 顺序分配,控制台自身的端口必须落在该范围之外。
Console 默认仍只监听 127.0.0.1。容器或反向代理部署需要监听非回环地址时,必须配置至少 16 位的管理员 Token,否则 Console 会拒绝启动:
export ANYDOCS_CONSOLE_HOST=0.0.0.0
export ANYDOCS_CONSOLE_AUTH_TOKEN='<random-token-at-least-16-characters>'
anydocs-ask console --workspace /runtime --port 4100
浏览器在 /login 输入 Token 后会获得 12 小时有效的 HttpOnly 签名会话 Cookie。Token 不会写入 Cookie;修改 Token 并重启 Console 会立即使旧会话失效。生产环境应始终经 HTTPS 反向代理访问。
单项目容器可通过 ANYDOCS_CONSOLE_ATTACHED_PROJECT 与 ANYDOCS_CONSOLE_ATTACHED_PORT 将 Console 附着到同一网络命名空间中已经运行的 Ask 服务,避免加载第二份 embedding 模型:
export ANYDOCS_CONSOLE_ATTACHED_PROJECT=docs
export ANYDOCS_CONSOLE_ATTACHED_PORT=3100
直接启动一个 HTTP 服务供 Reader 调用,不经过控制台:
# 启动服务(首次运行会自动初始化 ~/anydocs-ask-runtime/)
pnpm dev serve ./fixtures/starter-docs --port 3100
# 健康检查
curl http://localhost:3100/v1/health
# → {"status":"ok","warm":true,...}
# 提问
curl -X POST http://localhost:3100/v1/ask \
-H "Content-Type: application/json" \
-d '{"question":"鉴权怎么做?","lang":"zh"}'
<projectRoot> 的两种写法所有 CLI 子命令的第一个位置参数均为 <projectRoot>,指向一个 anydocs 项目目录(须包含 anydocs.config.json、pages/、navigation/)。支持两种形式,按是否含路径分隔符自动区分:
| 写法 | 示例 | 解析方式 | 适用场景 |
|---|---|---|---|
裸名称(不含 /) | my-docs | 从 projects.json 查找对应路径 | 已通过 workspace add 注册 |
| 文件系统路径 | ./fixtures/starter-docs、/abs/path | 按字面路径解析(相对路径基于 cwd) | 临时运行,无需注册 |
# 一次性注册
pnpm dev workspace add ./fixtures/starter-docs --name starter-docs
# 用裸名(已注册)
pnpm dev serve starter-docs --port 3100
pnpm dev eval starter-docs
# 用路径(无需注册)
pnpm dev serve ./fixtures/starter-docs --port 3100
pnpm dev serve /Users/me/work/product-docs
无论哪种写法,所有运行时数据(索引、runs、golden 集、报告)均写入 <workspace>/state/<projectId>/,源码仓库始终保持干净(双根分离,见 ARCH §16.1)。
POST /v1/ask
// 请求
{
"question": "如何鉴权?", // 必填,≤ 20,000 字
"lang": "zh", // 必填,"zh" | "en"
"context": { // 可选
"current_page_id": "auth", // 用户当前所在页面
"scope_id": "nav:zh.json:3" // 将检索范围限定到某个导航子树
}
}
// 正常响应
{
"type": "answer",
"answer_id": "ans_…",
"session_id": "sess_…", // 0.2+ multi-turn round-trip;client 回传同值即续聊
"answer_md": "…markdown…",
"answer_lang": "zh",
"citations": [
{
"citation_id": "cit_1",
"title": "鉴权",
"breadcrumb": […],
"url": "/zh/auth",
"snippet": "…"
}
],
"translation_notice": null // 跨语言降级时非 null
}
// 错误响应
{ "type": "error", "code": "invalid_question", "message": "…" }
POST /v1/ask/stream — 与 /v1/ask 同 body,返回 SSE token-by-token。事件类型:token / citations / answer / error。Reader 公网 UI 和 Widget chat-page 均走该端点。
POST /v1/ask/feedback — 提交 👍 / 👎 / 答错纠正(β 显式反馈)。需 feedback.enabled=true 才落 SQLite。
// 请求
{
"answer_id": "ans_…", // 必填
"rating": "up" | "down", // 必填
"comment": "答错了,应该是 …", // 可选,答错纠正文本
"session_id": "sess_…" // 可选,关联 multi-turn 会话
}
// 响应:{ "ok": true } 或 { "ok": false, "code": "...", "message": "..." }
GET /widget/v1.js + GET /widget/chat — 嵌入式 Widget 的 host bundle 与 iframe chat 页(RFC 0004)。需 widget.enabled=true 才挂;调用必须带 X-Project-Key header + origin 在 widget.allowedOrigins 白名单内,否则按 widget_disabled / invalid_project_key / origin_not_allowed / rate_limited 拒绝。
GET /v1/health — 预热完成后返回 {"status":"ok"},预热期间返回 {"status":"warming"};Reader 发起首次提问前应轮询此接口。
POST /mcp — MCP 知识库接口(RFC 0007),把本项目文档暴露成可被 Claude Code / Cursor 等 agent 调用的 MCP server,走 Streamable HTTP 无状态传输。默认关闭,需在 anydocs.ask.json 开 mcp.enabled=true。三个 tool:
| tool | 作用 | 成本 |
|---|---|---|
search | 混合检索,返回相关片段 + 来源页 + URL + breadcrumb | 无 LLM(只开此 tool 可不配 API Key) |
ask | 合成答案 + 校验过的 citations | 消耗服务端 LLM |
fetch_page | 按 page_id 取整页原文 | 无 LLM |
// anydocs.ask.json
{
"mcp": {
"enabled": true,
"tools": ["search", "ask"], // 想省 LLM 成本可只留 ["search"]
"rateLimitPerMinute": 60,
"allowedOrigins": [] // 浏览器型客户端的 Origin 白名单(server-to-server 留空)
}
}
独立的 Intent Router 只处理需要上下文消解或语义压缩的问题。无历史的短问题,以及 带明确 API 路径、错误码或异常名的诊断输入,会直接走确定性快路径,避免回答前再调用 一次大模型;其余路由结果按“问题 + 最近三轮历史”做进程内 TTL 缓存。长日志仍会先 脱敏,本地提取器保留接口路径、错误码、字段名和首尾空格等原始线索。密钥、Token、 签名和密码不会发送给 Router、Embedding 或回答模型,也不会以明文写入 Traffic 日志。
鉴权用 bearer token,走环境变量 ANYDOCS_MCP_TOKEN(密钥不入配置文件);设置后调用须带 Authorization: Bearer <token>,否则 401。未设置则端点开放——仅适合 loopback / 可信内网(此时端口无关的 DNS-rebinding Host 守卫生效)。在 MCP 客户端里注册(以 Claude Code 为例):
claude mcp add --transport http anydocs-ask http://127.0.0.1:3100/mcp \
--header "Authorization: Bearer $ANYDOCS_MCP_TOKEN"
全局安装(
npm install -g @anydocs/ask)后anydocs-ask <cmd>直接可用。从源码运行时,把下方所有anydocs-ask <cmd>换成pnpm dev <cmd>(仓库根目录),或pnpm build后用node dist/cli.js <cmd>。
# 服务
anydocs-ask serve <projectRoot> [--port 3100] [--host 127.0.0.1]
anydocs-ask reindex <projectRoot>
anydocs-ask status <projectRoot>
# 工作区管理(默认路径 ~/anydocs-ask-runtime/,可用 --workspace 或 $ANYDOCS_ASK_WORKSPACE 覆盖)
anydocs-ask workspace init
anydocs-ask workspace ls
anydocs-ask workspace add <path> [--name <name>] # 注册到 projects.json
anydocs-ask workspace rm <name> # 移除注册(保留 state 数据)
# 查询记录(每次 /v1/ask 追加一行;ARCH §16.4)
anydocs-ask runs tail <projectRoot> [--n 50]
anydocs-ask runs export <projectRoot> --since <when> [--format jsonl|csv]
# 评测闭环(ARCH §16.3 / §16.5 / §16.6)
anydocs-ask golden generate <projectRoot> [--from structure|runs] [--limit N]
[--since 14d] [--no-llm-rewrite] [--force]
anydocs-ask golden review <projectRoot> [--reviewer <name>]
anydocs-ask golden import <projectRoot> --file <jsonl> [--replace]
anydocs-ask eval <projectRoot> [--baseline <path>]
anydocs-ask analyze runs <projectRoot> [--since 7d]
# 反馈闭环(0.2+,RFC 0001 / 0006;详见 ARCH §15)
anydocs-ask feedback status <projectRoot> # 计数 β/γ 行 + 反馈先验状态
anydocs-ask feedback export <projectRoot> # SQLite → inbox/*.md,git 友好
anydocs-ask feedback import <projectRoot> # 审过 inbox/*.md → approved.jsonl
anydocs-ask feedback diagnose <projectRoot> # RFC 0006 A+ 失败查询聚类 → suggestions/cluster_*.md
[--threshold N] # 反馈数量下限(默认 aplus.threshold=50)
[--observation-window 28d] # 时间窗(默认 aplus.observationWindow)
[--shadow] # 强制写到 suggestions/.shadow/ 子目录
[--dry-run] # 跑全流程不写盘
golden import is intended for source-controlled, hand-curated eval sets.
Relative --file paths are resolved from <projectRoot>, then written into
the runtime workspace under <workspace>/state/<projectId>/golden/cases.jsonl.
--since 接受 ISO 日期(2026-04-01)、ISO 时间戳,或时长简写(7d / 48h / 30m)。
anydocs.ask.json(可选)在 <projectRoot> 放置 anydocs.ask.json 可覆盖默认配置(模型、检索权重、CORS 域名等),所有字段均为可选。完整字段列表见 ARCHITECTURE.md §9。
项目也可以追加自定义 Prompt 说明,用于按文档站的业务语境特调回答风格;核心的“只基于片段回答 / 必须引用 / 不编造”规则不会被覆盖。也可在 Web Console 的项目页 Prompt settings 里编辑。为避免 prompt 过大,保存时会把换行/多空格压成单空格,并限制 assistantName 最多 80 字符、systemInstructions 最多 20 条、每条最多 500 字符。
{
"prompt": {
"assistantName": "Cregis AI 助手",
"systemInstructions": [
"Payment Engine 主要用于订单、收款、托管收银台、支付回调和订单状态查询。",
"WaaS 主要用于钱包、地址、充值、归集、提币和链上资产管理。",
"回答时先给直接结论,再给必要步骤或注意事项。"
]
}
}
按 RFC 引入顺序列;所有段默认 整段 off,flip enabled 后才生效。完整字段语义与默认值见 ARCHITECTURE.md §9。
{
// Intent Router(默认 ON);model=null 时复用主回答模型
"router": {
"enabled": true,
"model": null, // 可填网关支持的更小、更快模型
"fastPathMaxChars": 240, // 0 = 关闭确定性快路径
"cacheTtlMs": 300000,
"cacheMaxEntries": 512
},
// RFC 0001 §3 — β 显式 + γ 隐式反馈通道(写库 + reranker 先验)
"feedback": {
"enabled": false, // 整段开关
"implicitSignals": "session-only", // γ 信号范围
"rerankerWeight": 0.15 // 反馈先验进 §6 步骤 4 的权重
},
// RFC 0003 — 多轮对话(默认 ON,0.2.0 起 design partner 自然多轮可用)
"multiTurn": {
"enabled": true,
"historyTurns": 3 // history 拼进 prompt 的最近轮数 [1, 20]
},
// RFC 0005 — citation 语义校验(异步 fire-and-forget,复用主 LLM)
"citationSemanticCheck": {
"enabled": false,
"mode": "shadow" // "shadow" | "enforce"(0.4 H1 升级才接通 enforce)
},
// RFC 0004 — 嵌入式 Ask Widget(host bundle + iframe chat)
"widget": {
"enabled": false,
"rateLimitPerMinute": 60, // per (project_key, origin) token bucket
"allowedOrigins": [] // 白名单 origin,空数组 = 一律拒
},
// RFC 0006 — A+ 失败查询诊断(聚类 + 建议生成)
"aplus": {
"enabled": false, // 0.4.0 GA 由 operator flip
"threshold": 50, // 反馈数量产品门槛
"observationWindow": "28d", // 4 周观察窗
"embedSimilarityThreshold": 0.65 // bge-m3 cosine 聚类阈值
},
// RFC 0007 — MCP 知识库接口(POST /mcp,Streamable HTTP 无状态)
"mcp": {
"enabled": false,
"tools": ["search", "ask"], // search(无LLM) / ask(耗LLM) / fetch_page
"rateLimitPerMinute": 60, // per (token|origin) token bucket
"allowedOrigins": [] // 浏览器型客户端的 Origin 白名单
// 鉴权 token 走 env ANYDOCS_MCP_TOKEN,不入此文件
}
}
面向公开发布的开发者文档与产品手册,为终端用户提供精准问答。每个进程对应一个 anydocs 项目,多项目通过多端口独立部署。多语言是一等公民,当前支持 zh / en,同语言优先,跨语言时自动翻译降级(详见 PRD §4.8)。
pnpm install
pnpm dev serve ./fixtures/starter-docs # 直接运行源码(--experimental-strip-types)
pnpm dev console # 启动 Web 控制台
pnpm test # node --test
pnpm typecheck
pnpm build # 输出到 dist/
依赖:Node ≥ 20,pnpm ≥ 8。实现进度与变更历史见 CHANGELOG.md。
MIT
165 commits
55 commits
TypeScript
96.1%
CSS
3.4%