配置说明
配置优先级
Markitai 使用以下优先级顺序(从高到低):
- 命令行参数
- 环境变量
- 配置文件
- 默认值
配置文件
Markitai 按以下顺序查找配置文件:
--config参数指定的路径MARKITAI_CONFIG环境变量./markitai.json(当前目录)~/.markitai/config.json(用户主目录)
初始化配置
# 交互式配置向导(推荐)
markitai init
# 快速模式(生成默认配置)
markitai init --yes
# 在指定位置创建全局配置
markitai init --local # 创建 ./markitai.json查看配置
# 列出所有设置
markitai config list
markitai config list --format json # JSON(默认)
markitai config list --format table # Rich 表格视图
markitai config list --format yaml # YAML(需要 pyyaml:uv add pyyaml)
markitai config list --show-secrets # 显示原始秘密值
# 获取特定值
markitai config get llm.enabled
# 设置值
markitai config set llm.enabled true
# 交互式编辑器(引导式菜单)
markitai config edit
# 验证配置
markitai config validate
markitai config validate ./markitai.json # 验证指定文件config list 默认会递归遮罩秘密值,包括嵌套的 API 密钥、Token、Cookie、认证信息及所有自定义 HTTP Header 值。自定义 api_base 只显示 origin。--show-secrets 仅供本机检查,不要把它的完整输出贴到 issue、聊天、CI 日志或其他共享渠道。
完整配置示例
{
"llm": {
"enabled": false,
"model_list": [
{
"model_name": "default",
"litellm_params": {
"model": "gemini/gemini-flash-lite-latest",
"api_key": "env:GEMINI_API_KEY"
}
}
],
"router_settings": {
"routing_strategy": "simple-shuffle",
"num_retries": 2,
"timeout": 120
},
"concurrency": 10,
"max_requests_per_document": 50,
"max_cost_per_document_usd": 0,
"max_vision_pages_per_document": 0,
"pure": false,
"keep_base": false
},
"image": {
"alt_enabled": false,
"desc_enabled": false,
"compress": true,
"quality": 75,
"format": "jpeg",
"max_width": 1920,
"max_height": 99999,
"filter": {
"min_width": 50,
"min_height": 50,
"min_area": 5000,
"deduplicate": true
},
"stdout_persist": true,
"stdout_persist_dir": "~/.markitai/assets",
"stdout_fetch_external": false
},
"ocr": {
"enabled": false,
"lang": "en",
"per_page_routing": true
},
"office": {
"macos_fallback": true
},
"screenshot": {
"enabled": false,
"screenshot_only": false,
"viewport_width": 1920,
"viewport_height": 1080,
"quality": 75,
"max_height": 10000
},
"cache": {
"enabled": true,
"no_cache": false,
"no_cache_patterns": [],
"max_size_bytes": 536870912,
"global_dir": "~/.markitai"
},
"batch": {
"concurrency": 10,
"url_concurrency": 5,
"scan_max_depth": 5,
"scan_max_files": 10000,
"state_flush_interval_seconds": 10,
"heavy_task_limit": 0
},
"fetch": {
"strategy": "auto",
"remote_consent": "always",
"defuddle": {
"timeout": 30,
"rpm": 20
},
"playwright": {
"timeout": 30000,
"wait_for": "domcontentloaded",
"extra_wait_ms": 3000,
"wait_for_selector": null,
"cookies": null,
"reject_resource_patterns": null,
"extra_http_headers": null,
"user_agent": null,
"http_credentials": null,
"session_mode": "isolated",
"session_ttl_seconds": 600
},
"jina": {
"api_key": null,
"timeout": 30,
"rpm": 20,
"no_cache": false,
"target_selector": null,
"wait_for_selector": null
},
"cloudflare": {
"api_token": null,
"account_id": null,
"timeout": 30000,
"wait_until": "networkidle0",
"cache_ttl": 0,
"reject_resource_patterns": null,
"convert_enabled": false,
"user_agent": null,
"cookies": null,
"wait_for_selector": null,
"http_credentials": null
},
"policy": {
"enabled": true,
"max_strategy_hops": 5,
"strategy_priority": null,
"local_only_patterns": [],
"inherit_no_proxy": true
},
"domain_profiles": {},
"fallback_patterns": ["x.com", "twitter.com", "instagram.com", "facebook.com", "linkedin.com", "threads.net"]
},
"output": {
"dir": null,
"on_conflict": "rename",
"allow_symlinks": false,
"report": null
},
"log": {
"level": "INFO",
"format": "text",
"dir": null,
"rotation": "10 MB",
"retention": "7 days"
},
"security": {
"pdf_sanitize": "warn"
},
"history": {
"record": false
},
"prompts": {
"dir": "~/.markitai/prompts"
}
}TIP
使用 env:VAR_NAME 语法在配置文件中引用环境变量。对于 JINA_API_KEY、CLOUDFLARE_API_TOKEN 和 CLOUDFLARE_ACCOUNT_ID,也可以直接设置环境变量(或写入 .env),无需在配置文件中声明,markitai 会自动读取。
环境变量
API 密钥
| 变量 | 说明 |
|---|---|
OPENAI_API_KEY | OpenAI API 密钥 |
ANTHROPIC_API_KEY | Anthropic (Claude) API 密钥 |
GEMINI_API_KEY | Google Gemini API 密钥 |
DEEPSEEK_API_KEY | DeepSeek API 密钥 |
OPENROUTER_API_KEY | OpenRouter API 密钥 |
JINA_API_KEY | Jina Reader API 密钥 |
CLOUDFLARE_API_TOKEN | Cloudflare API Token(Browser Rendering / Workers AI) |
CLOUDFLARE_ACCOUNT_ID | Cloudflare Account ID |
Markitai 设置
| 变量 | 说明 |
|---|---|
MARKITAI_CONFIG | 配置文件路径 |
MARKITAI_LOG_DIR | 日志文件目录 |
MARKITAI_LOG_FORMAT | 日志格式覆盖(text 或 json) |
MARKITAI_STATIC_HTTP | 静态 HTTP 后端:httpx(默认)或 curl_cffi(TLS 指纹伪装) |
MARKITAI_LANG | CLI 语言覆盖(en 或 zh) |
MARKITAI_PURE | 启用 pure 模式(1、true 或 yes) |
MARKITAI_RECORD_HISTORY | 将 CLI 运行记录到 markitai serve 历史(1、true、yes 或 on;已设置但为假值表示显式关闭)。可被 --record-history / --no-record-history 覆盖;会覆盖配置项 history.record |
MARKITAI_NO_REMOTE_FETCH | 硬性禁用远程提取,包括显式远程 -s 策略(1、true 或 yes) |
MODEL | 无 model_list 配置时的单模型覆盖 |
.env 文件加载
Markitai 按以下顺序自动加载 .env 文件(先加载的值优先):
./.env(当前工作目录,项目级)~/.markitai/.env(用户主目录,全局兜底)
项目级 .env 优先级更高,允许按项目覆盖全局设置。
LLM 配置
支持的提供商
任何 LiteLLM 提供商均可使用——OpenAI、Anthropic、Google、DeepSeek、OpenRouter、Ollama(本地)等。基于订阅的本地提供商通过各自的 CLI 认证,无需 API key:
| 提供商 | 前缀 | 认证方式 | 额外依赖 |
|---|---|---|---|
| Claude Agent | claude-agent/ | Claude Code CLI 登录 | markitai[claude-agent] |
| GitHub Copilot | copilot/ | Copilot CLI 登录 | markitai[copilot] |
| ChatGPT | chatgpt/ | 首次使用时 OAuth 设备码授权(无需 CLI) | — |
CLI 安装:curl -fsSL https://claude.ai/install.sh | bash(Claude Code;Windows:irm https://claude.ai/install.ps1 | iex),curl -fsSL https://gh.io/copilot-install | bash(Copilot;Windows:winget install GitHub.Copilot)。
Gemini 接入方式
Gemini:使用直连 API 密钥(gemini/,见下方“模型命名”)或通过 OpenRouter 接入(openrouter/google/...)。
模型命名
使用 LiteLLM 模型命名规范:
provider/model-name示例:
openai/gpt-5.6anthropic/claude-sonnet-4-6gemini/gemini-flash-lite-latestdeepseek/deepseek-v4-flashollama/llama3.2claude-agent/sonnet(本地,需要 Claude Code CLI)copilot/gpt-5.6(本地,需要 Copilot CLI)chatgpt/gpt-5.6(本地,需要 ChatGPT 订阅)
markitai 自动选用的默认模型
markitai init、设置向导和凭据自动探测都会选各家的便宜快速档;能用厂商维护的别名就用别名,这样厂商发新版不会让配置失效。受限预览版模型不会被自动选中。
| 提供商 | 默认模型 |
|---|---|
| Claude Code CLI | claude-agent/sonnet |
| GitHub Copilot | copilot/claude-haiku-4.5 |
| ChatGPT | chatgpt/gpt-5.6 |
| Anthropic | anthropic/claude-haiku-4-5 |
| OpenAI | openai/gpt-5.6-luna |
| Gemini | gemini/gemini-flash-lite-latest |
| DeepSeek | deepseek/deepseek-v4-flash |
| OpenRouter | openrouter/google/gemini-3.1-flash-lite |
配置 model_list 即可覆盖。
Claude Agent SDK 支持的模型:
- 别名(推荐):
sonnet、opus、haiku、inherit - 完整模型字符串:
claude-sonnet-4-6、claude-opus-4-6、claude-opus-4-5-20251101
GitHub Copilot SDK 支持的模型:
- 支持 Copilot 订阅可用的所有模型(o1/o3 推理模型除外)
- 例如:
gpt-5.6、claude-sonnet-4.6、gemini-3.1-pro-preview等 - 可用性取决于您的 Copilot 订阅计划
ChatGPT 支持的模型:
gpt-5.6、gpt-5.6-codex、codex-mini等
已下线模型
以下模型已被厂商下线,不再响应请求:
gpt-4o、gpt-4.1、gpt-4.1-mini、o4-mini、gpt-5、gpt-5.1、gpt-5.2
配置了也只会在启动时告警,markitai 不会替你改写模型。告警里给出的是你所在提供商的默认模型(见 markitai 自动选用的默认模型),下线日期只在 litellm 收录了的情况下才显示。
本地提供商支持 Vision
本地提供商(claude-agent/、copilot/、chatgpt/)通过文件附件支持图片分析(--alt、--desc)。请确保使用支持 vision 的模型(如 copilot/gpt-5.6、chatgpt/gpt-5.6)。
本地提供商故障排除
常见错误和解决方案:
| 错误 | 解决方案 |
|---|---|
| "SDK 未安装" | uv add markitai[copilot] 或 uv add markitai[claude-agent] |
| "CLI 未找到" | 安装并认证 CLI 工具(Copilot CLI、Claude Code) |
| "未认证" | 运行 copilot auth login 或 claude auth login。也可:为 Copilot 设置 COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN,为 Claude 设置 CLAUDE_CODE_USE_BEDROCK=1/CLAUDE_CODE_USE_VERTEX=1/CLAUDE_CODE_USE_FOUNDRY=1。ChatGPT 首次使用时自动触发 OAuth。 |
| "速率限制" | 等待后重试,或检查订阅额度 |
| "请求超时" | 超时是自适应的;处理非常大的文档可能需要更长时间 |
使用 markitai doctor 检查认证状态并获取解决方案提示。
自定义 API 端点
使用 api_base 覆盖提供商的默认 API 端点。该值直接传递给 LiteLLM,适用于任何 LiteLLM 支持的提供商(OpenAI、Anthropic、Gemini、Azure 等)。支持与 api_key 相同的 env:变量名 语法:
{
"llm": {
"model_list": [
{
"model_name": "default",
"litellm_params": {
"model": "openai/your-model-name",
"api_key": "env:YOUR_API_KEY",
"api_base": "https://your-api-endpoint.com/v1"
}
}
]
}
}示例:
// 本地 Ollama
{
"model": "ollama/llama3.2",
"api_base": "http://localhost:11434"
}
// Azure OpenAI —— "azure/<...>" 填你的 Azure 部署名(你在 Azure Portal 自定义的别名),不是模型 ID
{
"model": "azure/your-deployment-name",
"api_key": "env:AZURE_API_KEY",
"api_base": "https://your-resource.openai.azure.com",
"api_version": "2025-02-01-preview"
}
// DeepSeek
{
"model": "deepseek/deepseek-v4-flash",
"api_key": "env:DEEPSEEK_API_KEY",
"api_base": "https://api.deepseek.com/v1"
}
// 任何 OpenAI 兼容的提供商
{
"model": "openai/custom-model",
"api_key": "env:CUSTOM_API_KEY",
"api_base": "https://your-proxy-or-provider.com/v1"
}
// 引用环境变量
{
"model": "anthropic/claude-sonnet-4-6",
"api_key": "env:ANTHROPIC_API_KEY",
"api_base": "env:ANTHROPIC_BASE_URL"
}TIP
常见用例包括自托管推理服务器(vLLM、Ollama、LocalAI)、区域 API 代理和第三方 API 网关。
本地提供商与 api_base
api_base 配置字段不适用于本地提供商(claude-agent/、copilot/、chatgpt/)。这些提供商作为 CLI 子进程运行或使用 OAuth,内部管理 API 端点:
- Claude Agent: 设置
ANTHROPIC_BASE_URL覆盖 API 端点。如果同时设置了ANTHROPIC_API_KEY,CLI 将使用它进行直接 API 访问而非订阅认证。其他路由选项:CLAUDE_CODE_USE_BEDROCK=1、CLAUDE_CODE_USE_VERTEX=1、CLAUDE_CODE_USE_FOUNDRY=1。 - GitHub Copilot: 端点由 Copilot CLI 内部管理,不可覆盖。基于令牌的认证请设置
COPILOT_GITHUB_TOKEN、GH_TOKEN或GITHUB_TOKEN。 - ChatGPT: 使用 OpenAI Responses API 端点,通过 LiteLLM 内置 OAuth Device Code Flow 认证。
Vision 模型
对于图片分析(--alt、--desc),Markitai 自动路由到支持视觉的模型。视觉能力默认自动检测自 litellm,大多数模型无需手动配置。
如需显式覆盖自动检测,设置 supports_vision:
{
"llm": {
"model_list": [
{
"model_name": "default",
"litellm_params": {
"model": "gemini/gemini-flash-lite-latest",
"api_key": "env:GEMINI_API_KEY"
},
"model_info": {
"supports_vision": true // 可选:省略时自动检测
}
}
]
}
}模型 Token 上限
litellm_params 和 model_info 都支持可选的 token 上限覆盖:
{
"model_name": "default",
"litellm_params": {
"model": "gemini/gemini-flash-lite-latest",
"api_key": "env:GEMINI_API_KEY",
"max_tokens": 8192
},
"model_info": {
"max_tokens": 8192,
"max_input_tokens": 1000000
}
}| 字段 | 默认值 | 说明 |
|---|---|---|
litellm_params.max_tokens | null | 覆盖该模型每次调用请求的最大输出 token 数 |
model_info.max_tokens | null | 最大输出 token 元数据;省略时从 litellm 自动检测 |
model_info.max_input_tokens | null | 最大输入/上下文 token 元数据;省略时从 litellm 自动检测 |
路由设置
配置 Markitai 如何在多个模型间分发请求:
{
"llm": {
"router_settings": {
"routing_strategy": "simple-shuffle",
"num_retries": 2,
"timeout": 120,
"fallbacks": []
},
"concurrency": 10,
"max_requests_per_document": 50,
"max_cost_per_document_usd": 0,
"max_vision_pages_per_document": 0
}
}| 设置 | 选项 | 默认值 | 说明 |
|---|---|---|---|
routing_strategy | simple-shuffle, least-busy, usage-based-routing, latency-based-routing | simple-shuffle | 标准模型的选择策略;本地 provider(claude-agent/、copilot/ 等)始终按权重随机 |
num_retries | ≥0 | 2 | 每个请求的传输层重试次数,由 markitai 自己的重试循环执行(LiteLLM 内部重试保持关闭) |
timeout | 秒 | 120 | 请求超时时间(自适应计算的基础值) |
fallbacks | list | [] | LiteLLM 模型组回退,如 [{"default": ["backup"]}]。请求从 default 组进入,其他组名的模型只经回退获得流量(仅标准模型)。留空 = 全部模型合并进 default 组 |
concurrency | ≥1 | 10 | 最大并发 LLM 请求数 |
max_requests_per_document | ≥0 | 50 | 断路器:单文档 LLM 请求数上限(重试全部计入)。触发后跳过该文档剩余增强,保留未增强产物。超大文档请调高;0 关闭 |
max_cost_per_document_usd | ≥0 | 0 | 断路器:单文档花费上限(美元)。每次拿到回答后计费——调用前无法预知价格——所以它约束的是该文档后续还能花多少,而非跨过阈值的那一次。触发后跳过剩余增强,保留未增强产物。0 关闭 |
max_vision_pages_per_document | ≥0 | 0 | 断路器:单文档发给视觉模型的页图数上限。发送前检查,超限的文档一分钱不花,改为不带视觉增强地转换。同时限制纯截图 URL 转换读取的截图分块数(只读前几块)。0 关闭 |
模型权重
model_list 中每个模型的 litellm_params 支持 weight 参数来控制流量分配:
{
"model_name": "default",
"litellm_params": {
"model": "gemini/gemini-flash-lite-latest",
"api_key": "env:GEMINI_API_KEY",
"weight": 10
}
}| 值 | 行为 |
|---|---|
weight: 0 | 禁用:模型完全排除在路由之外 |
weight: 1(默认) | 正常优先级 |
weight: 10 | 被选中的概率是 weight=1 模型的 10 倍 |
设置 weight: 0 可临时禁用某个模型而无需删除其配置。至少需要一个模型的 weight > 0,这一校验是在 LLM 路由器真正启动时(首次使用 LLM 时)才会执行,而不是在 markitai config validate 阶段,所以全部模型 weight 都为 0 的配置能通过校验,但会在首次实际使用时失败。
自适应超时
本地 provider(claude-agent/、copilot/、chatgpt/)使用基于请求复杂度的自适应超时计算:
- 基础超时:最小 60 秒,最大 600 秒
- 考虑因素:提示词长度、图片存在/数量、预期输出 token 数
- 计算公式:
timeout = 60 + (提示词字符数 / 500)- 如有预期输出 token 数:加
tokens / 4 - 如有图片:
timeout *= 1.5(这一步也会连带放大上面的输出 token 项),多张图片时额外加(图片数 - 1) * 10秒 - 限制在 [60, 600] 秒范围内
这可以防止大文档处理超时,同时保持短请求的响应速度。
提示缓存(Claude Agent)
Claude Agent provider 对长度达到 4096 字符(约 4KB)及以上的系统提示词自动启用提示缓存。这通过缓存常用的系统提示词前缀来降低 API 成本。
TIP
提示缓存是透明的,无需配置。使用 markitai cache stats --verbose 查看缓存统计。
图片配置
控制图片处理和压缩:
{
"image": {
"alt_enabled": false,
"desc_enabled": false,
"compress": true,
"quality": 75,
"format": "jpeg",
"max_width": 1920,
"max_height": 99999,
"filter": {
"min_width": 50,
"min_height": 50,
"min_area": 5000,
"deduplicate": true
}
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
alt_enabled | false | 通过 LLM 生成 alt 文本 |
desc_enabled | false | 生成图片描述文件 |
compress | true | 压缩图片 |
quality | 75 | JPEG/WebP 质量 (1-100) |
format | jpeg | 输出格式:jpeg, png, webp |
max_width | 1920 | 最大宽度(像素) |
max_height | 99999 | 最大高度(像素,实际无限制) |
filter.min_width | 50 | 跳过宽度小于此值的图片 |
filter.min_height | 50 | 跳过高度小于此值的图片 |
filter.min_area | 5000 | 跳过面积小于此值的图片 |
filter.deduplicate | true | 去除重复图片 |
stdout_persist | true | 将管道输出图片保存到持久化资产存储 |
stdout_persist_dir | ~/.markitai/assets | 持久化图片存储目录 |
stdout_fetch_external | false | 在 stdout 模式下下载外部图片 URL |
截图配置
为文档和 URL 启用截图捕获:
{
"screenshot": {
"enabled": false,
"screenshot_only": false,
"viewport_width": 1920,
"viewport_height": 1080,
"quality": 75,
"max_height": 10000,
"tile_height": 2000
}
}启用后(--screenshot 或 --preset rich):
- PDF/PPTX: 将每个页面/幻灯片渲染为 JPEG 图片
- URL: 使用 Playwright 捕获全页面截图
| 设置 | 默认值 | 说明 |
|---|---|---|
enabled | false | 启用截图捕获 |
screenshot_only | false | 仅捕获截图,跳过内容提取(对应 --screenshot-only CLI 标志) |
viewport_width | 1920 | URL 截图的浏览器视口宽度 |
viewport_height | 1080 | URL 截图的浏览器视口高度 |
quality | 75 | JPEG 压缩质量 (1-100) |
max_height | 10000 | 旧版单文件高度上限;当 tile_height 为 0 时使用 |
tile_height | 2000 | 更高的 URL 截图会按此高度切成纵向 tile(保持全宽),每块均为 VLM 可读,而不是被整体缩小成一张读不清的图 |
截图保存在输出目录的 .markitai/screenshots/ 子目录中。
TIP
对于 URL,启用 --screenshot 会在需要时自动将抓取策略升级为 playwright,确保页面完全渲染后再捕获。
预设
Markitai 包含三个内置预设(rich、standard、minimal)。您还可以在配置文件中定义自定义预设:
{
"presets": {
"my-preset": {
"llm": true,
"ocr": false,
"alt": true,
"desc": false,
"screenshot": true
}
}
}| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
llm | boolean | false | 启用 LLM 增强 |
ocr | boolean | false | 启用扫描文档 OCR |
alt | boolean | false | 生成图片 alt 文本 |
desc | boolean | false | 生成图片描述 |
screenshot | boolean | false | 启用截图捕获 |
通过 --preset CLI 标志使用自定义预设:
markitai document.pdf --preset my-presetOCR 配置
配置扫描文档的光学字符识别。Markitai 使用 RapidOCR(ONNX Runtime + OpenCV)进行 OCR 处理。
{
"ocr": {
"enabled": false,
"lang": "en",
"per_page_routing": true
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
enabled | false | 为 PDF 及独立图片启用 OCR |
lang | en | RapidOCR 语言代码 |
per_page_routing | true | 使用 --ocr 时,未被判定为扫描/乱码的页面保留原生文本层,仅对其余页面执行 OCR;关闭后对每一页都执行 OCR |
支持的语言代码:
en- 英语zh/ch- 中文(简体)ja/japan- 日语ko/korean- 韩语ar/arabic- 阿拉伯语th- 泰语latin- 拉丁语系
TIP
RapidOCR 已作为依赖包含,开箱即用,无需额外安装。
Office 配置
控制未安装 LibreOffice 时 macOS 上的 MS Office 备选方案。
{
"office": {
"macos_fallback": true
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
macos_fallback | true | macOS 上未安装 LibreOffice 时,通过 AppleScript 驱动已装的 Microsoft PowerPoint 完成 PPTX 幻灯片渲染 |
TIP
首次转换会触发每个应用一次性的 macOS 自动化授权弹窗。无头环境(SSH、CI)无法响应弹窗,建议关闭此备选。
批处理配置
控制并行处理:
{
"batch": {
"concurrency": 10,
"url_concurrency": 5,
"scan_max_depth": 5,
"scan_max_files": 10000,
"state_flush_interval_seconds": 10,
"heavy_task_limit": 0
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
concurrency | 10 | 最大并发文件转换数 |
url_concurrency | 5 | 最大并发 URL 抓取数(与文件分离) |
scan_max_depth | 5 | 最大目录扫描深度 |
scan_max_files | 10000 | 单次运行最大处理文件数 |
state_flush_interval_seconds | 10 | 批处理状态持久化到磁盘的间隔(秒) |
heavy_task_limit | 0 | CPU 密集任务限制(0 = 根据内存自动检测) |
TIP
URL 抓取使用独立的并发池,因为 URL 可能有较高延迟(如浏览器渲染的页面)。这可以防止慢速 URL 阻塞本地文件处理。
URL 抓取配置
配置 URL 的抓取方式:
{
"fetch": {
"strategy": "auto",
"remote_consent": "always",
"playwright": {
"timeout": 30000,
"wait_for": "domcontentloaded",
"extra_wait_ms": 3000
},
"jina": {
"api_key": "env:JINA_API_KEY",
"timeout": 30,
"rpm": 20,
"no_cache": false,
"target_selector": null,
"wait_for_selector": null
},
"cloudflare": {
"api_token": "env:CLOUDFLARE_API_TOKEN",
"account_id": "env:CLOUDFLARE_ACCOUNT_ID"
},
"fallback_patterns": ["twitter.com", "x.com", "instagram.com", "facebook.com", "linkedin.com", "threads.net"]
}
}抓取策略
| 策略 | 说明 |
|---|---|
auto | 自动检测:本地优先顺序(static → playwright → defuddle → jina → cloudflare);已知 SPA/重 JS 域名则改用 playwright → defuddle → jina → cloudflare → static。详见 Fetch Policy 指南 |
static | 使用静态 HTTP 抓取和内置 webextract(快速,无 JS) |
defuddle | 使用 Defuddle API 提取干净内容(免费,无需认证) |
playwright | 使用 Playwright 处理 JS 渲染的页面(支持 SPA) |
jina | 使用 Jina Reader API |
cloudflare | 使用 Cloudflare Browser Rendering /content API(取回渲染后的 HTML,本地提取) |
远程抓取同意
对于公网 URL,auto 可以在无需确认的情况下回退到远程提取服务。标准域名仍会先尝试本地策略。每个进程第一次准备使用远程服务时,Markitai 会先在 stderr 输出说明,再把当前 URL 交给链路中的下一个服务。说明会完整列出该进程级决定覆盖的服务:defuddle.md、Jina、Cloudflare、FxTwitter 与 Twitter oEmbed。各服务按顺序逐个尝试,不会同时收到该 URL。
对于公网 X/Twitter 状态或文章 URL,本地 DOM 提取失败后,Playwright 可能依次尝试 FxTwitter 与 Twitter oEmbed。这项增强与其他远程服务共用同一个进程级同意决定:在 ask 模式下,它自己也可以弹出那一次共享确认;本次运行中已经做出的决定会被直接沿用;无法询问时则跳过。fetch.remote_consent=never 与 MARKITAI_NO_REMOTE_FETCH=1 都会禁用它。
私网、本机、内网及自带认证信息的 URL 绝不会使用远程提取,即使显式指定远程策略也不例外。认证信息包括 URL userinfo,以及 query 或 fragment 中的 Token、签名、Credential、密码、API Key 与授权码等敏感参数。在 auto 策略链中,匹配 fetch.policy.local_only_patterns 或 NO_PROXY 的域名也只会留在本机处理(启用 inherit_no_proxy 时)。对于仍属公网的 URL,显式传入非 auto 远程 -s 参数表示有意覆盖这些基于模式的规则。仅在配置文件中设置远程 fetch.strategy 时,仍受 fetch.remote_consent 控制,并使用相同的首次远程揭露。
| 设置 | 选项 | 默认值 | 说明 |
|---|---|---|---|
fetch.remote_consent | ask, always, never | always | always:公网 URL 可直接使用远程后备,并在第一次远程尝试前输出说明;ask:每个进程在交互式终端中询问一次,非交互环境跳过全部远程提取服务(含上述 X/Twitter 增强);never:仅使用本地策略 |
MARKITAI_NO_REMOTE_FETCH=1(或 true/yes)是硬性禁用开关:即使传入 -s defuddle、-s jina 或 -s cloudflare,也不会使用远程提取。未设置该环境变量时,显式传入这些 CLI 参数表示本次运行选择该服务,并可为其他公网 URL 覆盖 fetch.remote_consent=never 及 local_only_patterns/NO_PROXY;但私网、本机及自带认证信息 URL 的保护仍然生效。
Playwright 设置
| 设置 | 默认值 | 说明 |
|---|---|---|
timeout | 30000 | 页面加载超时(毫秒) |
wait_for | domcontentloaded | 等待条件:load, domcontentloaded, networkidle |
extra_wait_ms | 3000 | JS 渲染额外等待时间 |
session_mode | isolated | 会话模式:isolated(每个请求新建上下文)、domain_persistent(同域名复用上下文) |
session_ttl_seconds | 600 | 持久化会话的 TTL(秒) |
wait_for_selector | null | 提取前等待的 CSS 选择器 |
cookies | null | 设置 Cookie:[{name, value, domain, path}] |
reject_resource_patterns | null | 屏蔽匹配的资源:["**/*.css"] |
extra_http_headers | null | 额外 HTTP 请求头:{"Accept-Language": "zh-CN"} |
user_agent | null | 自定义 User-Agent 字符串 |
http_credentials | null | HTTP 认证凭据:{username, password} |
Jina 设置
| 设置 | 默认值 | 说明 |
|---|---|---|
api_key | null | Jina Reader API 密钥(支持 env: 语法) |
timeout | 30 | 请求超时(秒) |
rpm | 20 | 每分钟请求速率限制 |
no_cache | false | 禁用 Jina 服务端缓存 |
target_selector | null | 定位特定页面内容的 CSS 选择器 |
wait_for_selector | null | 提取前等待的 CSS 选择器 |
Defuddle 设置
Defuddle 从网页中提取干净的文章内容,移除广告、侧边栏和导航等干扰元素。返回带有丰富 YAML frontmatter(title、author、published、description、word_count)的 Markdown。
| 设置 | 默认值 | 说明 |
|---|---|---|
timeout | 30 | 请求超时(秒) |
rpm | 20 | 每分钟请求速率限制 |
{
"fetch": {
"defuddle": {
"timeout": 30,
"rpm": 20
}
}
}TIP
Defuddle 免费且无需 API 密钥或认证。适合文章类网站的默认选择。
Cloudflare 设置
Cloudflare 提供两项能力,各自独立选择:
- Browser Rendering(
-s cloudflare):/contentAPI 取回渲染后的 HTML,再通过与其他策略相同的原生 webextract 流水线本地提取,用于 URL 转 Markdown - Workers AI toMarkdown(
-b cloudflare):用于文件转 Markdown(PDF、Office、CSV、XML、图片)
{
"fetch": {
"cloudflare": {
"api_token": "env:CLOUDFLARE_API_TOKEN",
"account_id": "env:CLOUDFLARE_ACCOUNT_ID",
"timeout": 30000,
"wait_until": "networkidle0",
"cache_ttl": 0,
"reject_resource_patterns": null,
"user_agent": null,
"cookies": null,
"wait_for_selector": null,
"http_credentials": null,
"convert_enabled": false
}
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
api_token | null | Cloudflare API Token(支持 env: 语法) |
account_id | null | Cloudflare Account ID(支持 env: 语法) |
timeout | 30000 | Browser Rendering 超时(毫秒) |
wait_until | networkidle0 | BR 等待事件:load, domcontentloaded, networkidle0 |
cache_ttl | 0 | BR 缓存 TTL(秒,0 = 不缓存) |
reject_resource_patterns | null | 屏蔽匹配正则的资源:["/\\.css$/"] |
user_agent | null | Browser Rendering 自定义 User-Agent |
cookies | null | 导航前设置的 Cookie:[{"name": "k", "value": "v", "url": "..."}] |
wait_for_selector | null | 页面加载后等待的 CSS 选择器(如 "#content") |
http_credentials | null | HTTP Basic Auth:{"username": "u", "password": "p"} |
convert_enabled | false | 启用 Workers AI toMarkdown 文件转换 |
TIP
Browser Rendering 在 Free 计划上可用。Workers AI toMarkdown 对 PDF/Office/CSV/XML 转换免费;图片转换使用 Neurons 配额。
凭据获取方式:
Account ID:登录 Cloudflare Dashboard,Account ID 显示在 URL 中(
dash.cloudflare.com/<account_id>/...),或在任意域名的 Overview 页面右侧边栏中。API Token:进入 My Profile → API Tokens,点击 Create Token,选择 Custom token 模板,添加以下权限:
权限 访问级别 用途 Account / Cloudflare Workers AI Read toMarkdown文件转换Account / Browser Rendering Edit /contentURL 渲染将 Account Resources 设为目标账户,创建后复制 Token。
启用 Browser Rendering:在 Cloudflare Dashboard 中进入 Workers & Pages → Browser Rendering,按提示启用(Free 计划可用)。
export CLOUDFLARE_API_TOKEN="your-api-token"
export CLOUDFLARE_ACCOUNT_ID="your-account-id"限制与注意事项
- 并发限制:Free 计划允许 2 个并发浏览器实例。Markitai 会自动串行化 CF BR 请求,并在收到 429 限流时指数退避重试,因此高
url_concurrency值是安全的,但不会加速 CF BR 抓取。 - 站点兼容性:有严格反爬措施的站点(如 x.com、twitter.com)可能通过 CF BR 返回 400 错误。对这些站点请使用
-s playwright或-s jina。 - 文件转换质量:对于有本地 converter 的格式(PDF、DOCX、XLSX 等),CF Workers AI
toMarkdown的输出质量通常低于本地 converter(如格式还原不够精确、无法提取图片等)。使用-b cloudflare时如果有更好的本地 converter 可用会输出警告。CFtoMarkdown最适合本地没有 converter 的格式(.numbers、.ods、.svg等)。
抓取策略引擎
策略引擎基于域名特征和历史记录智能排序抓取策略。详见 Fetch Policy 指南。
{
"fetch": {
"policy": {
"enabled": true,
"max_strategy_hops": 5
}
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 启用智能策略排序 |
max_strategy_hops | 5 | 放弃前最多尝试的策略数 |
strategy_priority | null | 自定义全局策略顺序(覆盖默认优先级) |
local_only_patterns | [] | 限制为本地策略的域名/IP 模式(NO_PROXY 语法) |
inherit_no_proxy | true | 将 NO_PROXY 环境变量合并到 local_only_patterns |
域名配置
为特定域名配置抓取覆盖:
{
"fetch": {
"domain_profiles": {
"x.com": {
"wait_for_selector": "[data-testid=tweetText]",
"wait_for": "domcontentloaded",
"extra_wait_ms": 1200,
"prefer_strategy": "playwright"
}
}
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
wait_for_selector | null | 内容提取前等待的 CSS 选择器 |
wait_for | null | 等待条件覆盖:load, domcontentloaded, networkidle(未设置时继承全局 fetch.playwright.wait_for) |
extra_wait_ms | null | 额外等待时间覆盖(毫秒,未设置时继承全局 fetch.playwright.extra_wait_ms) |
prefer_strategy | null | 首选策略:static, defuddle, playwright, cloudflare, jina |
strategy_priority | null | 该域名的自定义策略顺序(覆盖全局和 prefer_strategy) |
skip_auto_scroll | false | 对单内容页面(推文、issue、文档)跳过自动滚动 |
reject_resource_patterns | null | 阻止 Playwright 导航中匹配这些 URL 模式的资源(如 ["**/analytics/**"]) |
Markitai 内置了 x.com/twitter.com 和 github.com 的域名配置。为同一域名设置自己的 domain_profiles 条目会整体替换内置配置而非逐字段合并,除非自行重复声明,否则内置调优会丢失。
回退模式
匹配这些模式的网站被视为 SPA/JS 重度依赖站点,在策略顺序中提升浏览器渲染的优先级:
{
"fetch": {
"fallback_patterns": ["x.com", "twitter.com", "instagram.com", "facebook.com", "linkedin.com", "threads.net"]
}
}代理
抓取时优先使用 HTTPS_PROXY / HTTP_PROXY / ALL_PROXY(NO_PROXY 为绕过列表)。都未设置时读取系统代理:Windows 的 Internet 设置、macOS 的网络设置,以及 Linux 上当前 GNOME/Unity 或 KDE 桌面的手动 HTTP 代理(含绕过列表)。PAC/WPAD、仅 SOCKS 和带认证的桌面设置不会导入——这类情况和无桌面的机器一样,请设置环境变量。
缓存配置
Markitai 使用全局缓存,存储在 ~/.markitai/cache.db。
{
"cache": {
"enabled": true,
"no_cache_patterns": [],
"max_size_bytes": 536870912,
"global_dir": "~/.markitai"
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
enabled | true | 启用 LLM 结果缓存 |
no_cache | false | 跳过读取缓存但仍写入(相当于 --no-cache 标志) |
no_cache_patterns | [] | 跳过缓存的 glob 模式 |
max_size_bytes | 536870912 (512MB) | 最大缓存大小 |
global_dir | ~/.markitai | 全局缓存目录 |
缓存命令
# 查看缓存统计
markitai cache stats
# 查看详细统计(条目、按模型分组)
markitai cache stats --verbose
# 指定显示数量
markitai cache stats --verbose --limit 50
# 清除缓存
markitai cache clear
markitai cache clear -y # 跳过确认禁用缓存
# 整次运行禁用
markitai document.pdf --no-cache
# 对特定文件/模式禁用
markitai ./docs --no-cache-for "*.pdf"
markitai ./docs --no-cache-for "file1.pdf,reports/**"输出配置
控制输出文件处理:
{
"output": {
"on_conflict": "rename"
}
}| 设置 | 选项 | 默认值 | 说明 |
|---|---|---|---|
dir | - | null | 输出目录 |
on_conflict | rename, overwrite, skip | rename | 处理已存在文件的方式 |
allow_symlinks | - | false | 允许输出路径中的符号链接 |
report | true, false, null | null | 是否写入 JSON 转换报告。null(默认)仅在批量/URL 批量任务时写入;true/false 强制对每次运行开启/关闭 |
profile | rag, obsidian, okf, null | null | 面向下游消费者的输出 Profile。null 保持输出不变 |
wikilinks | true, false | false | 在 obsidian profile 下将本地图片引用改写为 wikilink(![[assets/x.png]]) |
日志配置
配置日志行为:
{
"log": {
"level": "INFO",
"format": "text",
"dir": null,
"rotation": "10 MB",
"retention": "7 days"
}
}| 设置 | 默认值 | 说明 |
|---|---|---|
level | INFO | 日志级别:DEBUG, INFO, WARNING, ERROR, CRITICAL |
format | text | 日志格式:text(可读文本)或 json(结构化) |
dir | null | 日志文件目录(未设置时自动检测) |
rotation | 10 MB | 文件超过此大小时轮转 |
retention | 7 days | 删除早于此时间的日志 |
安全配置
控制 PDF 隐藏文本的处理。这是 LLM 流水线的一种提示注入攻击面(白底白字、近零尺寸、零透明度或页外内容等本会被静默纳入提取结果的隐藏文本):
{
"security": {
"pdf_sanitize": "warn"
}
}| 设置 | 选项 | 默认值 | 说明 |
|---|---|---|---|
pdf_sanitize | off, warn, remove | warn | warn 会记录一条汇总提示,标明受影响的页码;remove 还会从输出中剥离匹配到的隐藏文本;off 禁用检测 |
自定义提示词
自定义不同任务的 LLM 提示词。每个提示词拆分为 system(角色定义)和 user(内容模板)两部分:
{
"prompts": {
"dir": "~/.markitai/prompts",
"cleaner_system": null,
"cleaner_user": null,
"image_caption_system": null,
"image_caption_user": null,
"image_description_system": null,
"image_description_user": null,
"image_analysis_system": null,
"image_analysis_user": null,
"document_process_system": null,
"document_process_user": null,
"document_vision_system": null,
"document_vision_user": null,
"url_enhance_system": null,
"url_enhance_user": null
}
}在提示词目录创建自定义提示词文件:
~/.markitai/prompts/
├── cleaner_system.md # 文档清理角色和规则
├── cleaner_user.md # 文档清理内容模板
├── image_caption_system.md # Alt 文本生成角色
├── image_caption_user.md # Alt 文本内容模板
├── document_process_system.md # 文档处理角色
└── url_enhance_system.md # URL 增强角色指定特定的提示词文件路径:
{
"prompts": {
"cleaner_system": "/path/to/my-cleaner-system.md",
"cleaner_user": "/path/to/my-cleaner-user.md"
}
}TIP
system/user 拆分可以防止 LLM 意外地将提示词指令包含在其输出中。system 提示词定义角色和规则,而 user 提示词包含实际要处理的内容。
中国大陆用户指南
安装脚本镜像加速
安装脚本会自动检测代理环境变量(HTTPS_PROXY / HTTP_PROXY / ALL_PROXY)。如果未检测到代理,会询问是否启用国内镜像加速,并提供以下镜像源选择:
| 镜像源 | PyPI | npm | 推荐地域 |
|---|---|---|---|
| 清华 TUNA(默认) | pypi.tuna.tsinghua.edu.cn | registry.npmmirror.com | 北方 / 通用 |
| 阿里云 | mirrors.aliyun.com | registry.npmmirror.com | 东部 |
| 腾讯云 | mirrors.cloud.tencent.com | mirrors.cloud.tencent.com | 南方 |
| 华为云 | repo.huaweicloud.com | mirrors.huaweicloud.com | 北方 |
Playwright 浏览器二进制文件统一使用 npmmirror CDN 镜像(cdn.npmmirror.com),这是目前唯一可靠的公共镜像。
你也可以在运行安装脚本前手动设置(以清华 TUNA 为例):
macOS / Linux / WSL (Bash/Zsh):
export UV_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple"
export PLAYWRIGHT_DOWNLOAD_HOST="https://cdn.npmmirror.com/binaries/playwright"
export NPM_CONFIG_REGISTRY="https://registry.npmmirror.com"Windows (PowerShell):
$env:UV_INDEX_URL = "https://pypi.tuna.tsinghua.edu.cn/simple"
$env:PLAYWRIGHT_DOWNLOAD_HOST = "https://cdn.npmmirror.com/binaries/playwright"
$env:NPM_CONFIG_REGISTRY = "https://registry.npmmirror.com"LLM API 访问
国内可用的 LLM 提供商及配置方式:
| 提供商 | 可用性 | 说明 |
|---|---|---|
| DeepSeek | 直连可用 | 无需代理,直接使用 deepseek/deepseek-v4-flash |
| Ollama | 完全离线 | 本地模型,使用 ollama/llama3.2 |
| API 代理服务 | 通过中转 | 通过 api_base 指向第三方中转服务 |
| OpenAI / Claude / Gemini | 需代理 | 需代理或 api_base 中转 |
使用 api_base 指向代理中转的示例配置:
{
"llm": {
"model_list": [
{
"model_name": "default",
"litellm_params": {
"model": "openai/gpt-5.6",
"api_key": "env:OPENAI_API_KEY",
"api_base": "https://your-api-proxy.com/v1"
}
}
]
}
}代理配置
如已有代理,设置环境变量即可对所有网络请求生效:
export HTTPS_PROXY="http://127.0.0.1:7890"
export HTTP_PROXY="http://127.0.0.1:7890"$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:HTTP_PROXY = "http://127.0.0.1:7890"TIP
设置了代理环境变量后,安装脚本会自动跳过镜像加速配置。