# 企业内网部署本地 AI QA 工程师：Ollama + LibreChat + Playwright MCP 实战

> **目标**：在一台企业内网 Linux 主机上，部署一套由 LibreChat、Ollama、Qwen3:8b 与 Playwright MCP 组成的浏览器测试助手。第一阶段只访问测试环境，只执行低风险、可回滚的 QA 操作，不接入生产写权限。

## 结论先行

这套方案适合做**探索性测试、测试步骤验证和用例草拟**，不适合替代确定性的 Playwright 回归测试流水线。正确的落地方式不是一开始就连接生产系统、Jira 和 GitHub，而是先在隔离测试环境里完成一个最小闭环：

1. 用户在 LibreChat 中提交明确的测试步骤；
2. Qwen3:8b 通过 Ollama 在内网完成推理；
3. Playwright MCP 在隔离浏览器中逐步操作测试站点；
4. 助手返回步骤数、通过/失败状态与证据位置；
5. 人工复核结果，再决定是否将稳定流程改写成正式 Playwright 测试。

原文在 16 GB RAM、无独立 GPU 的环境中，简单场景启动约需 1 分钟、完整执行约需 4–5 分钟。因此，首轮试点应以**隐私、可审计和探索效率**为目标，而不是追求比静态脚本更快。

## 来源与内容边界

- 原文：[*Build Your Own Local AI QA Engineer With Docker, Ollama, LibreChat, and Playwright MCP*](https://dzone.com/articles/local-ai-qa-engineer)
- 来源：DZone，2026-07-30；页面注明经 Faisal Khatri 授权发布
- 原文事实：Docker、Ollama、Qwen3:8b、LibreChat、Playwright MCP 的组合架构、基础配置、Agent 指令和两个测试示例。
- 本文提炼：把原文步骤整理成单机内网部署闭环，并补充验收标准与失败处理。
- 实践扩展：容器网络隔离、当前 Streamable HTTP 配置、镜像与模型离线转运、权限边界、审计和四周试点计划。这些是面向企业内网的补充，不是原文结论。

## 1. 适用范围与明确限制

### 适用

- 内部测试站点的页面巡检、表单验证和探索性测试；
- 将自然语言测试步骤快速验证后，再沉淀为正式自动化脚本；
- 数据不允许发送到公有云模型的团队；
- 小规模、低并发的 QA 试点。

### 暂不适用

- 生产环境写操作、支付、审批、删改数据；
- 无人工复核的持续自治测试；
- 需要秒级反馈的大规模回归测试；
- 仅凭 Agent 最终回答就判定测试通过；
- 将 Playwright MCP 当作网络或权限安全边界。其官方项目明确说明：MCP 服务本身不是安全边界。

## 2. 最小可用架构

```text
内网 QA 用户
    │ HTTPS / 内网统一认证
    ▼
反向代理或内网入口
    │
    ▼
LibreChat :3080
    ├── OpenAI-compatible API ──> Ollama :11434 ──> Qwen3:8b
    └── Streamable HTTP MCP ───> Playwright MCP :8931 ──> Headless Chromium
                                                       │
                                                       ▼
                                              仅允许访问测试域名
```

部署原则：

- 只把 LibreChat 的入口开放给内网用户；
- Ollama 的 `11434` 和 Playwright MCP 的 `8931` 只在 Docker 内部网络暴露，不映射到宿主机；
- 第一阶段不挂载宿主机业务目录，不提供 GitHub/Jira/数据库写工具；
- 浏览器使用隔离会话，不保存个人登录态；
- 测试账号使用最小权限，禁止复用生产账号。

## 3. 前置条件

建议基线：

- Linux x86_64 或 ARM64 主机；
- 16 GB RAM 起步，推荐 32 GB；
- 25 GB 以上可用 SSD 空间；
- Docker Engine 与 Docker Compose v2；
- Git；
- 能在准备阶段访问批准的镜像仓库和模型源，或已完成离线转运；
- 一个**非生产**测试站点及专用测试账号。

检查环境：

```bash
docker version
docker compose version
git --version
free -h
df -h
```

验收：以上命令均成功；可用内存和磁盘达到团队基线。

失败处理：若主机不足 16 GB RAM，不要直接扩大并发或上下文长度；先改用更小模型，或换到容量更高的试点主机。

## 4. 获取 LibreChat 并固定版本

```bash
sudo install -d -m 0750 /opt/local-ai-qa
sudo chown "$USER":"$USER" /opt/local-ai-qa
cd /opt/local-ai-qa

git clone https://github.com/danny-avila/LibreChat.git
cd LibreChat
cp .env.example .env
cp librechat.example.yaml librechat.yaml
cp docker-compose.override.yml.example docker-compose.override.yml
```

不要长期跟随浮动的 `main`、`latest` 或 `@latest`。试点验证通过后，应记录并固定：

```bash
git rev-parse HEAD
docker compose config --images
```

将 Git 提交号、镜像 digest、Qwen 模型 digest 写入内部变更记录。升级时重新做连通性与三个测试场景，而不是直接覆盖生产试点。

## 5. 配置内网服务

### 5.1 `librechat.yaml`

保留 LibreChat 示例文件中团队需要的其他配置，并合并下面的核心块：

```yaml
version: 1.3.13
cache: true

endpoints:
  custom:
    - name: "Ollama"
      apiKey: "ollama"
      baseURL: "http://ollama:11434/v1/"
      models:
        default:
          - "qwen3:8b"
        fetch: true
      titleConvo: true
      titleModel: "current_model"
      summarize: false
      summaryModel: "current_model"
      modelDisplayLabel: "Ollama"

mcpSettings:
  allowedAddresses:
    - "playwright-mcp:8931"

mcpServers:
  playwright:
    type: streamable-http
    url: "http://playwright-mcp:8931/mcp"
    timeout: 120000
    initTimeout: 30000
    requiresOAuth: false
    serverInstructions: |
      仅访问管理员批准的测试域名。
      每次只执行一个浏览器工具，等待结果后再继续。
      导航后重新获取页面快照，不复用旧页面状态。
      不下载文件，不访问宿主机文件，不进行生产写操作。
      失败时停止新动作，返回当前 URL、最后成功步骤和失败原因。
```

为什么使用 `streamable-http`：当前 LibreChat 文档已经支持 `streamable-http`，Playwright MCP 也提供 `/mcp` 服务端点；原文采用的 `/sse` 是兼容旧客户端的路径，不应作为新部署的默认选择。

### 5.2 `docker-compose.override.yml`

```yaml
services:
  api:
    volumes:
      - ./librechat.yaml:/app/librechat.yaml:ro
    depends_on:
      - ollama
      - playwright-mcp

  ollama:
    image: ollama/ollama:latest
    restart: unless-stopped
    volumes:
      - ollama-data:/root/.ollama
    expose:
      - "11434"
    environment:
      OLLAMA_NO_CLOUD: "1"
      OLLAMA_CONTEXT_LENGTH: "8192"
      OLLAMA_NUM_PARALLEL: "1"
      OLLAMA_MAX_QUEUE: "8"

  playwright-mcp:
    image: mcr.microsoft.com/playwright/mcp:latest
    restart: unless-stopped
    entrypoint: ["node", "/app/cli.js"]
    command:
      - "--headless"
      - "--browser"
      - "chromium"
      - "--no-sandbox"
      - "--host"
      - "0.0.0.0"
      - "--port"
      - "8931"
      - "--allowed-hosts"
      - "playwright-mcp:8931"
      - "--isolated"
      - "--block-service-workers"
      - "--output-mode"
      - "file"
      - "--output-dir"
      - "/tmp/playwright-output"
      - "--timeout-action"
      - "10000"
      - "--timeout-navigation"
      - "60000"
    expose:
      - "8931"
    tmpfs:
      - /tmp:size=1g,mode=1777
    security_opt:
      - no-new-privileges:true

volumes:
  ollama-data:
```

注意：

- 这里的 `latest` 只用于首次试装。通过验收后必须改成内部批准的不可变 tag 或 digest。
- `--no-sandbox` 是官方容器长驻示例使用的参数，但它削弱了浏览器进程隔离，因此容器和主机网络仍要视为真正的安全边界。
- 不要为 `ollama` 或 `playwright-mcp` 添加宿主机 `ports`；`expose` 只供 Compose 内部网络使用。
- 若企业要求 GPU 推理，应按批准的 NVIDIA Container Toolkit 方案单独评估；不要在 CPU 闭环尚未通过时同时引入 GPU 变量。

## 6. 静态检查与启动

先渲染最终 Compose 配置：

```bash
cd /opt/local-ai-qa/LibreChat
docker compose config > /tmp/local-ai-qa-compose.rendered.yaml
```

确认敏感服务没有发布到宿主机：

```bash
if grep -Eq 'published: (11434|8931)' /tmp/local-ai-qa-compose.rendered.yaml; then
  echo "FAIL: Ollama 或 Playwright MCP 被发布到宿主机"
  exit 1
fi

echo "PASS: 11434/8931 未发布到宿主机"
```

启动服务：

```bash
docker compose up -d
docker compose ps
```

预期：LibreChat 相关容器、`ollama` 和 `playwright-mcp` 均处于 `Up`；不应出现反复重启。

失败处理：

```bash
docker compose logs --tail=200 api
docker compose logs --tail=200 ollama
docker compose logs --tail=200 playwright-mcp
```

先修复第一个明确错误，不要通过无限增大 timeout 掩盖 DNS、模型缺失或 MCP 初始化失败。

## 7. 下载模型并验证推理

```bash
docker compose exec ollama ollama pull qwen3:8b
docker compose exec ollama ollama list
docker compose exec ollama ollama ps
```

从 LibreChat API 容器验证模型 API：

```bash
docker compose exec api node -e '
fetch("http://ollama:11434/api/tags")
  .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
  .then(x => {
    const names = (x.models || []).map(m => m.name);
    if (!names.some(n => n.startsWith("qwen3:8b"))) throw new Error("qwen3:8b missing");
    console.log("PASS", names);
  })
  .catch(e => { console.error("FAIL", e.message); process.exit(1); });
'
```

预期输出形态：

```text
PASS [ 'qwen3:8b' ]
```

然后登录 LibreChat，选择 `Ollama > qwen3:8b`，输入：

```text
只回答数字：2 + 2 等于多少？
```

验收：回答为 `4`；容器日志中没有外部模型 API 请求。

## 8. 验证 Playwright MCP 连接

从 API 容器检查 MCP 端点可达性：

```bash
docker compose exec api node -e '
fetch("http://playwright-mcp:8931/mcp", { method: "GET" })
  .then(r => {
    console.log("HTTP", r.status, "content-type", r.headers.get("content-type"));
    if (r.status >= 500) process.exit(1);
  })
  .catch(e => { console.error("FAIL", e.message); process.exit(1); });
'
```

这里的 GET 不一定完成 MCP 会话初始化；它只验证容器 DNS、端口和 HTTP 服务是否可达。真正的 MCP 协议验收应在 LibreChat 中完成：

1. 重启 API：`docker compose restart api`；
2. 登录 LibreChat；
3. 创建 Agent，模型选择 `Qwen3:8b`；
4. 为 Agent 启用 `playwright` MCP；
5. 保存后确认工具列表中出现 Playwright 浏览器工具。

失败处理：

- `ENOTFOUND playwright-mcp`：检查两个服务是否处于同一 Compose 网络；
- `ECONNREFUSED`：检查 MCP 容器日志与 `--host 0.0.0.0`；
- `403` 或 Host 校验失败：确认客户端使用 `playwright-mcp:8931`，并与 `--allowed-hosts` 完全一致；
- `/mcp` 不兼容：核对实际固定的 Playwright MCP 与 LibreChat 版本；只有在版本证据确认必须兼容旧协议时，才回退到 `type: sse` 与 `/sse`。

## 9. 配置 QA Agent 行为约束

将下面内容放入 LibreChat Agent 的 Instructions。它保留了原文的单步调用、导航后刷新状态、语义定位和失败停止原则，并增加企业内网边界。

```markdown
# 内网 QA Agent 执行规范

你是只操作测试环境的 QA 自动化助手。

## 范围
- 只执行用户明确列出的步骤，不新增业务动作。
- 只访问允许的测试域名；遇到其他域名立即停止。
- 禁止生产环境、支付、删除、审批、权限变更和批量写入。

## 工具调用
- 每次只调用一个 Playwright 工具。
- 等待当前工具返回后，再决定下一步。
- 任何交互前先获取当前页面的新快照，不猜测页面状态。

## 导航
- 点击链接、登录、提交、继续、保存或任何可能改变 URL 的动作后，等待页面加载和 URL 稳定。
- 导航后必须重新获取快照；不得继续使用旧页面引用。

## 定位
- 优先使用 role、label、text、placeholder、title、testid 等语义定位。
- 不使用 XPath、自动生成类名或 nth()，除非页面不存在更稳定的唯一标识。
- 交互前确认目标元素存在且唯一。

## 失败处理
- 任一工具失败后停止新动作。
- 重新检查当前 URL 和页面快照。
- 未确认页面状态前，不重复点击或提交。
- 最多重试一次；第二次失败后返回失败报告。

## 输出
- 返回：测试名称、总步骤数、逐步 PASS/FAIL、最后 URL、失败原因、证据文件名。
- 不能从最终页面直接证明的结果，标记为“未验证”，不得推测通过。
```

建议参数：Temperature `0.2`、Top P `0.85`。这些是原文试用参数，不是普适最优值；团队应依据固定测试集比较后再调整。

## 10. 三个试点场景

所有场景都应指向团队自己的隔离测试域名。下面用 `https://qa.example.internal` 作为占位符。

### 场景 A：只读页面巡检

目标：验证模型能正确导航、读取标题并停止，不产生写操作。

输入：

```text
测试名称：首页标题巡检
允许域名：qa.example.internal
步骤：
1. 打开 https://qa.example.internal/
2. 验证页面标题包含“测试环境”
3. 返回当前 URL 和验证结果
限制：不要点击任何按钮或链接
```

预期输出形态：

```text
测试名称：首页标题巡检
总步骤数：3
1. PASS - 已打开允许域名
2. PASS - 标题包含“测试环境”
3. PASS - 当前 URL: https://qa.example.internal/
结论：PASS
```

验收：访问域名正确、没有额外点击、结果包含明确证据而不是泛泛地说“完成”。

### 场景 B：测试账号登录

目标：验证表单定位、一次提交和登录后页面校验。

前置数据：由管理员创建无生产权限的测试账号；密码通过 LibreChat 的受控用户输入提供，不写入 Agent 指令、Markdown、日志或 Git。

输入：

```text
测试名称：测试账号登录
允许域名：qa.example.internal
步骤：
1. 打开 https://qa.example.internal/login
2. 使用标签定位“用户名”和“密码”字段
3. 填入本次会话提供的测试凭据
4. 点击一次“登录”
5. 等待导航完成并重新获取页面快照
6. 验证页面出现“测试账户概览”
限制：不要修改账户资料；登录失败后不要重复提交
```

验收：

- 只提交一次；
- 导航后重新获取页面状态；
- 成功时明确验证目标文本；
- 失败时停止，不循环尝试密码。

失败预期：若凭据错误，应返回 `FAIL - 登录失败，未重试`，而不是尝试猜测或更换账号。

### 场景 C：受控失败与恢复

目标：验证元素缺失时 Agent 会停止并报告，而不是幻觉点击。

输入：

```text
测试名称：缺失元素处理
允许域名：qa.example.internal
步骤：
1. 打开 https://qa.example.internal/
2. 查找文本为“这个按钮不存在”的按钮
3. 如果不存在，停止测试并返回当前 URL、页面标题和失败原因
限制：不要点击其他相似按钮，不要使用 nth() 猜测目标
```

预期输出形态：

```text
测试名称：缺失元素处理
总步骤数：3
1. PASS - 页面已打开
2. FAIL - 未找到唯一且可见的“这个按钮不存在”按钮
3. PASS - 已停止，没有执行替代点击
结论：FAIL（符合失败处理预期）
```

验收：没有替代点击、没有重复查找循环、没有把“找不到元素”改写成成功。

## 11. 一键预检脚本

创建 `/opt/local-ai-qa/LibreChat/scripts/preflight-local-ai-qa.sh`：

```bash
#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")/.."

docker compose config >/tmp/local-ai-qa-compose.rendered.yaml

if grep -Eq 'published: (11434|8931)' /tmp/local-ai-qa-compose.rendered.yaml; then
  echo "FAIL: sensitive service port published to host"
  exit 1
fi

docker compose ps --status running

docker compose exec -T api node -e '
Promise.all([
  fetch("http://ollama:11434/api/tags").then(r => {
    if (!r.ok) throw new Error(`ollama HTTP ${r.status}`);
    return r.json();
  }),
  fetch("http://playwright-mcp:8931/mcp").then(r => {
    if (r.status >= 500) throw new Error(`mcp HTTP ${r.status}`);
    return r.status;
  })
]).then(([tags, mcpStatus]) => {
  const names = (tags.models || []).map(m => m.name);
  if (!names.some(n => n.startsWith("qwen3:8b"))) {
    throw new Error("qwen3:8b missing");
  }
  console.log(JSON.stringify({
    status: "PASS",
    model: "qwen3:8b",
    mcp_http_status: mcpStatus
  }));
}).catch(e => {
  console.error(JSON.stringify({status: "FAIL", error: e.message}));
  process.exit(1);
});
'
```

授权并运行：

```bash
chmod 0750 scripts/preflight-local-ai-qa.sh
./scripts/preflight-local-ai-qa.sh
```

预期输出形态：

```json
{"status":"PASS","model":"qwen3:8b","mcp_http_status":406}
```

`mcp_http_status` 的具体非 5xx 状态可能随协议版本变化；预检只证明 HTTP 服务可达，不能替代 LibreChat 中的真实工具调用验收。

## 12. 内网安全与合规清单

上线试点前逐项确认：

- [ ] 镜像来自企业批准仓库，并记录 digest；
- [ ] 模型文件来自批准来源，并记录模型名称、大小与 digest；
- [ ] Ollama 已设置 `OLLAMA_NO_CLOUD=1`；
- [ ] `11434`、`8931` 未发布到宿主机或办公网；
- [ ] LibreChat 入口通过内网 TLS、统一认证或等效访问控制保护；
- [ ] 测试账号与生产账号隔离；
- [ ] 防火墙或代理只允许浏览器访问批准的测试域名；
- [ ] 第一阶段没有 GitHub、Jira、文件系统、数据库写工具；
- [ ] 不在 Prompt、Agent 指令、代码仓库和普通日志中保存密码或 Token；
- [ ] 每次执行保留步骤状态、最终 URL、失败原因和证据文件名；
- [ ] 任何生产写操作都必须另行评审，并加入人工确认与回滚；
- [ ] 已验证容器删除、模型回滚和配置恢复流程。

特别注意：Playwright MCP 的 `--allowed-hosts` 用于服务端 Host/DNS rebinding 检查，不是浏览器访问目标的完整网络隔离。真正的目标域名限制应由防火墙、出站代理、网络命名空间或专用测试网段执行。

## 13. 无互联网内网的离线转运

在可联网的受控准备机上：

```bash
docker pull ollama/ollama:latest
docker pull mcr.microsoft.com/playwright/mcp:latest
# LibreChat 仓库 compose 所需镜像也需先拉取：
docker compose pull

docker save -o local-ai-qa-images.tar \
  ollama/ollama:latest \
  mcr.microsoft.com/playwright/mcp:latest
sha256sum local-ai-qa-images.tar > local-ai-qa-images.tar.sha256
```

模型转运建议使用企业批准的内部模型仓库。若只能转移 Ollama 数据卷，应在准备机完成 `ollama pull qwen3:8b`，停止写入后导出数据卷，并在目标机恢复到新建卷；具体命令要根据企业备份工具和 Docker 数据目录制定，不要直接复制运行中的卷。

在内网目标机至少执行：

```bash
sha256sum -c local-ai-qa-images.tar.sha256
docker load -i local-ai-qa-images.tar
```

验收：校验和一致；目标机能够在无公网访问条件下启动镜像、列出 `qwen3:8b` 并通过预检。

## 14. 四周试点计划

### 第 1 周：单机闭环

- 完成容器部署与端口隔离；
- 跑通场景 A、B、C；
- 记录首次响应时间、总耗时、工具调用次数和失败类型；
- 不接入任何写工具。

### 第 2 周：小组试用

- 选 3–5 名 QA；
- 使用固定的 10–20 个测试任务；
- 对比 Agent 结果与人工结果；
- 统计误点击、重复提交、元素幻觉和超时。

### 第 3 周：固化边界

- 固定镜像与模型 digest；
- 固化允许域名、测试账号权限和日志保留策略；
- 将高频且稳定的测试转写成普通 Playwright 测试，不让 Agent 每次重新推理；
- 完成回滚演练。

### 第 4 周：有限扩展

- 扩大测试页面范围，但不扩大生产权限；
- 只有在审计证据充分时，才评估只读 Jira 或只读 GitHub 工具；
- 不通过“答案看起来正确”判断工具调用可靠性；必须核查工具轨迹和页面证据。

## 15. 验收标准

试点最低通过线：

1. **部署**：所有容器稳定运行，敏感端口未对宿主机发布；
2. **推理**：Qwen3:8b 可在内网调用，Ollama 云功能关闭；
3. **工具**：LibreChat 能连接 Playwright MCP，并完成真实浏览器调用；
4. **行为**：场景 A、B 正常完成，场景 C 按预期失败并停止；
5. **安全**：无生产凭据、无生产写权限、无未批准公网出口；
6. **证据**：每次运行能给出步骤级 PASS/FAIL、最终 URL 和失败原因；
7. **性能**：团队接受实测延迟；若不能接受，优先调整模型、硬件或场景，不把探索性 Agent 当静态回归测试替代品。

## 16. 回滚

停止并保留数据用于排查：

```bash
cd /opt/local-ai-qa/LibreChat
docker compose down
```

回滚配置：

```bash
git status
git diff -- librechat.yaml docker-compose.override.yml
git checkout -- librechat.yaml docker-compose.override.yml
```

若这些文件是企业自有配置，不应直接 `git checkout`；应从已评审备份或配置仓库恢复。确认不再需要数据后，删除模型卷属于破坏性操作，必须走审批，不要在普通故障处理中执行 `docker compose down -v`。

## 17. 原文方法覆盖清单

| 原文方法 | 是否纳入 | 落点 | 若遗漏原因 |
| :--- | :---: | :--- | :--- |
| Docker 部署 LibreChat | 是 | 第 4–6 节 | — |
| Ollama 安装/服务与 Qwen3:8b | 是 | 第 5、7 节 | 改为 Compose 内部服务，避免内网暴露 API |
| LibreChat 连接 Ollama | 是 | 第 5.1 节 | — |
| Playwright MCP 服务 | 是 | 第 5.2、8 节 | 使用当前 Streamable HTTP；保留 SSE 回退说明 |
| MCP 允许地址配置 | 是 | 第 5.1 节 | 使用当前 `allowedAddresses` 精确地址规则 |
| 创建 LibreChat Agent | 是 | 第 8、9 节 | — |
| 单工具串行、导航后刷新、语义定位、失败停止 | 是 | 第 9 节 | — |
| Playwright 首页验证 | 是 | 场景 A | 替换为企业测试域名占位符 |
| ParaBank 登录示例 | 是，改写 | 场景 B | 改为企业测试账号，避免依赖公网演示站 |
| Jira/GitHub/数据库扩展 | 暂不纳入执行 | 第 1、14 节 | 首阶段只读低风险试点，不增加写权限 |
| macOS Homebrew 安装 Ollama | 否 | — | 本教程目标为企业内网 Linux 容器部署 |
| 旧版 SSE `/sse` 默认连接 | 否，保留回退 | 第 5.1、8 节 | 当前 LibreChat 支持 Streamable HTTP，新部署优先 `/mcp` |
| `--allowed-hosts "*"` | 否 | 第 5.2 节 | 企业部署不应关闭 Host 检查 |

## 18. 证据级别

- `static_publish_ok: true`：Markdown/HTML 已生成；本地结构检查、远端 Markdown/HTML 非空检查和 SHA-256 一致性检查均通过。
- `mock_code_run_ok`：不适用；本文没有伪造 Mock 服务来替代真实组件。
- `real_backend_contract_ok`：教程配置依据当前 Ollama、LibreChat、Playwright MCP 官方文档做了静态核对，但应在目标团队固定版本后再次执行 `docker compose config`。
- `real_backend_smoke_ok`：未执行。本文没有在用户目标内网主机上启动 Ollama、LibreChat 或 Playwright MCP；只有目标环境完成第 6–10 节验收后才能标记为真。

## 参考资料

- [DZone 原文](https://dzone.com/articles/local-ai-qa-engineer)
- [LibreChat：配置 Ollama](https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints/ollama)
- [LibreChat：MCP Servers 配置](https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/mcp_servers)
- [Playwright MCP 官方仓库](https://github.com/microsoft/playwright-mcp)
- [Ollama FAQ 与服务配置](https://docs.ollama.com/faq)
- [Ollama API：列出模型](https://docs.ollama.com/api/tags)
