Skip to content

feat(provider):Ollama 本地 Provider 与能力探测(#48) - #63

Merged
Qiyuanqiii merged 4 commits into
mainfrom
codex/issue-48-ollama-provider
Aug 15, 2026
Merged

Qiyuanqiii merged 4 commits into
mainfrom
codex/issue-48-ollama-provider

Conversation

@Qiyuanqiii

Copy link
Copy Markdown
Member

背景

Issue #48 要求为离线、本地优先场景实现 Ollama Provider,并对模型是否支持工具、JSON、视觉和上下文窗口做显式探测,避免因为“本地模型存在”就假设其具备完整 Agent 能力。基线里 llm.Provider、Router、Registry 与 Harness qualification 已留好扩展点,但所有外部 Provider 都是凭证驱动,且能力来自静态配置而非真实探测。

本次改动

1. 无凭证、显式 loopback 的 Ollama Provider

新增 internal/llm/ollama.go:

  • 只有同时显式配置 CYBERAGENT_OLLAMA_BASE_URL(仅 loopback http,默认 http://127.0.0.1:11434)与 CYBERAGENT_OLLAMA_MODEL 才启用;缺省永不探测、永不扫描局域网;
  • Base URL 校验拒绝 HTTPS、非 loopback host、userinfo、query、fragment 与路径前缀;HTTP client 强制 Proxy=nil(即使进程环境有 HTTP_PROXY)并拒绝 redirect;
  • 原生 /api/tags 模型列表、/api/chat(同步 + NDJSON 流式)、/api/show 能力探测;
  • 流式状态机覆盖文本增量、完整 tool_calls(合成确定性 ID)、done/done_reason(closed set)、daemon token 计数、超限文本、重复 tool_calls、done 之后的尾随事件、截断流与取消;
  • usage 优先采用 daemon 计数,缺失时按字符/4 向上取整保守估算;
  • 稳定错误映射:404+not found → model_not_found、out of memory → capacity、rate limit → rate_limit、连接类 → network,服务未启动时给出固定的可解释诊断(不携带 host/路径/payload)。

2. 能力探测与失败关闭

  • capabilities 字段存在即表示模型已探测;tools/vision 来自 closed set,context window 只接受 model_info 中数值型 <family>.context_length 的最大值并限界;
  • 能力未知一律按不支持处理;探测在路由选择、qualification 与 diagnostic 前 best-effort 执行,失败不阻塞操作,之后仍失败关闭;
  • 探测到的 context window 通过 Router.SetContextWindow(source=ollama_probe)进入真实预算规划。

3. no-tool 安全路径

  • DescribeModelHarness 输出 ollama_chat transport:tools 未确认 → ToolStrategy=none、JSON 未确认 → JSONStrategy=none;
  • Provider 在 prepareRequest 层再设一道防线:向未确认 tools 能力的模型发送 Tool schema 直接失败,绝不透传 schema,也绝不伪造 tool call;
  • no-tool 模型只能走无工具安全路径(fanout/plain chat),不会进入错误的 Tool loop。

4. 入口接线

  • Registry 新增 ProviderKindOllama,OpenAPI 的 provider 路径枚举与 transport_protocol 枚举加入 ollama/ollama_chat;
  • CLI、HTTP/OpenAPI、Desktop 与 Web 复用现有通用模型控制面(provider list/test/qualify、model set、模型可用性视图),Web 客户端的 kind/transport 校验同步接受新枚举;
  • credential 枚举保持四位——Ollama 无凭证,不属于系统凭证允许列表;configs/models.yaml 只保留文档级示例。

测试覆盖

fake-server 离线测试(internal/llm/ollama_test.go)覆盖:构造器拒绝非 loopback/HTTPS/路径/凭证/代理 transport;代理禁用与 redirect 拒绝;/api/tags 能力已知/未知语义;/api/show 探测(tools/vision/context,字符串与非数值忽略);同步 Chat、usage 计数与估算、tool call ID/arguments 规范化;错误分类(model_not_found/capacity/500 正文升级);no-tool 安全路径(fake server 断言零 Tool schema 到达);NDJSON 流式文本/usage/tool calls、done 后尾随事件、截断流、上下文取消;服务不可达的稳定诊断。Registry 侧新增:显式 loopback 启用、非 loopback/缺模型 → invalid_configuration、路由选择时探测并写入 harness profile 与 context window。

验证结果

已在只包含本 issue 改动的隔离工作树中完成:

  • go build ./...、go vet ./...
  • 全仓 go test -timeout 30m ./...(internal/analyzer 的低权限 helper 在本机服务会话以 0xc0000142 环境性失败,该包零改动、与本次 diff 无关)
  • go test -race ./internal/llm ./internal/modelregistry
  • Web:strict TypeScript、59 个测试文件 235 项测试、Vite production build、npm run check:api(OpenAPI 再生确定一致)全部通过
  • 本机未安装 Ollama:真实 smoke 为 usage 文档化的可选人工步骤(ollama pull llama3.2:3b → 设两个 CYBERAGENT_OLLAMA_* 变量 → model set/provider test/provider qualify),fake-server 测试可完全离线运行

安全边界与非目标

  • 不自动安装 Ollama、不 pull 模型、不修改系统服务、不扫描局域网;
  • 不把本地模型视为可信模型:输出仍走 Policy、redaction、budget 与 Tool Gateway;
  • 非 loopback、代理绕过、重定向与隐式启用一律拒绝;
  • 能力不明时按不支持处理,绝不伪造调用。

详细设计与不变量记录见 ADR 0100。

Closes #48

… probing

Add a keyless local Provider that connects only to an explicitly configured loopback endpoint (CYBERAGENT_OLLAMA_BASE_URL + CYBERAGENT_OLLAMA_MODEL). Non-loopback hosts, HTTPS, URL credentials, queries, fragments, path prefixes, redirects, and proxy-bearing transports are rejected. The native /api/tags model list, /api/chat (sync and NDJSON streaming with cancellation/truncation/trailing-event rejection), /api/show capability probing, usage estimation, and stable error mapping (model_not_found/capacity/rate_limit/network plus an explainable service-unreachable diagnostic) are implemented. tools/vision/JSON/context capabilities stay unknown and therefore unsupported until the daemon reports them; the no-tool safe path rejects tool schemas at both the Harness (ToolStrategy none) and Provider layers. The registry wires kind ollama and transport ollama_chat into CLI/HTTP/OpenAPI/Desktop/Web, probes capabilities before route selection, qualification, and diagnostics, and keeps the credential allowlist at four providers.
… (ADR 0100)

Bilingual README, usage manual, task book, project status, resume memory, and the ADR document the explicit loopback enablement, fail-closed capability semantics, the no-tool safe path, usage estimation, stable diagnostics, and the optional real-Ollama smoke steps.
@Qiyuanqiii
Qiyuanqiii merged commit c4a0641 into main Aug 15, 2026
5 checks passed
@NanaseInori
NanaseInori deleted the codex/issue-48-ollama-provider branch September 16, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(provider): Ollama 本地 Provider 与能力探测

1 participant