This commit is contained in:
XiaoHuo888-hue 2026-10-08 00:07:33 -04:00 • committed by GitHub
commit 63c4c7213f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 123 additions and 0 deletions

View file

@ -151,6 +151,11 @@ EOF
Basic file operations, BM25 search, wikilink traversal, and reading proactive topics can run without LLM credentials.
`LLM_BACKEND` selects the provider wrapper registered in `reme/components/as_llm` (default `openai`). You can also use
[OrcaRouter](https://www.orcarouter.ai), an OpenAI-compatible gateway, with `LLM_BACKEND=orcarouter`,
`LLM_MODEL_NAME=orcarouter/auto`, and an `LLM_API_KEY` from OrcaRouter; `LLM_BASE_URL` then defaults to
`https://api.orcarouter.ai/v1`.
> [!NOTE]
> To enable embedding-based semantic retrieval, uncomment `components.as_embedding` and
> `components.embedding_store` in [`reme/config/default.yaml`](reme/config/default.yaml), then change

View file

@ -142,6 +142,11 @@ EOF
基础文件读写、BM25 检索、wikilink 遍历和 proactive topics 读取不需要 LLM 凭证,可以跳过此步骤并直接启动服务。
`LLM_BACKEND` 选择 `reme/components/as_llm` 中注册的 provider wrapper(默认 `openai`)。也可以接入
[OrcaRouter](https://www.orcarouter.ai)(兼容 OpenAI 协议的中转网关):设 `LLM_BACKEND=orcarouter`、
`LLM_MODEL_NAME=orcarouter/auto`,并用 OrcaRouter 的 `LLM_API_KEY`;`LLM_BASE_URL` 可缺省,
默认 `https://api.orcarouter.ai/v1`。
> [!NOTE]
> 如需启用基于 embedding 的语义检索,请取消 [`reme/config/default.yaml`](reme/config/default.yaml) 中
> `components.as_embedding` 和 `components.embedding_store` 的注释,并将

View file

@ -47,6 +47,19 @@ EOF
You can initially omit the LLM configuration if you only need basic file operations and BM25 retrieval.
`LLM_BACKEND` selects the provider wrapper registered in
`reme/components/as_llm`. Besides the built-in providers (`openai`, `anthropic`, `deepseek`,
`dashscope`, `gemini`, `moonshot`, `ollama`, `xai`), you can point at
[OrcaRouter](https://www.orcarouter.ai), an OpenAI-compatible gateway, by setting:
```bash
LLM_BACKEND=orcarouter
LLM_MODEL_NAME=orcarouter/auto
LLM_API_KEY=sk-orca-...
```
`LLM_BASE_URL` stays optional — when unset it defaults to `https://api.orcarouter.ai/v1`.
---
## Start the Service

View file

@ -46,6 +46,17 @@ EOF
只跑基础文件读写和 BM25 检索,可以先不配。
`LLM_BACKEND` 选择 `reme/components/as_llm` 中注册的 provider wrapper。除内置 provider(`openai`、`anthropic`、`deepseek`、`dashscope`、`gemini`、`moonshot`、`ollama`、`xai`)外,也可以接入兼容 OpenAI 协议的中转网关
[OrcaRouter](https://www.orcarouter.ai):
```bash
LLM_BACKEND=orcarouter
LLM_MODEL_NAME=orcarouter/auto
LLM_API_KEY=sk-orca-...
```
`LLM_BASE_URL` 可不填,缺省时默认 `https://api.orcarouter.ai/v1`。
---
## 启动

View file

@ -3,6 +3,11 @@ EMBEDDING_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_API_KEY=sk-xxx
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
# OpenAI-compatible gateway: LLM_BACKEND=orcarouter
# LLM_API_KEY=sk-orca-...
# LLM_MODEL_NAME=orcarouter/auto
# LLM_BASE_URL is optional and defaults to https://api.orcarouter.ai/v1
# Optional data-source mirrors. Unset variables use the official services.
# HF_MIRROR_URL=https://hf-mirror.com
# ARXIV_MIRROR_URL=https://export.arxiv.org

View file

@ -1,5 +1,7 @@
"""LLM model wrappers for AgentScope."""
from typing import Literal
from agentscope.credential import (
AnthropicCredential,
CredentialBase,
@ -12,6 +14,7 @@ from agentscope.credential import (
XAICredential,
)
from agentscope.model import ChatModelBase
from pydantic import ConfigDict, Field, field_validator
from ..base_component import BaseComponent
from ..component_registry import R
@ -66,6 +69,46 @@ class OpenAIAsLLM(BaseAsLLM):
credential_cls = OpenAICredential
_ORCAROUTER_BASE_URL = "https://api.orcarouter.ai/v1"
class OrcaRouterCredential(OpenAICredential):
"""OpenAI-compatible credential for the OrcaRouter gateway.
OrcaRouter exposes an OpenAI-compatible ``chat/completions`` endpoint at
``https://api.orcarouter.ai/v1``. The shared LLM config passes
``base_url: ${LLM_BASE_URL:-}``, so an unset ``LLM_BASE_URL`` yields an
empty string; this credential falls back to the hosted gateway in that
case while still allowing a custom/self-hosted endpoint.
"""
model_config = ConfigDict(
title="OrcaRouter API",
)
type: Literal["orcarouter_credential"] = "orcarouter_credential"
"""The credential type."""
base_url: str = Field(
default=_ORCAROUTER_BASE_URL,
description="The base URL for the OrcaRouter API.",
)
"""The base URL for the OrcaRouter API."""
@field_validator("base_url", mode="before")
@classmethod
def _default_base_url(cls, value: str | None) -> str:
"""Fall back to the hosted gateway when the shared config leaves the field empty."""
return value or _ORCAROUTER_BASE_URL
@R.register("orcarouter")
class OrcaRouterAsLLM(BaseAsLLM):
"""OrcaRouter chat model wrapper (OpenAI-compatible gateway)."""
credential_cls = OrcaRouterCredential
@R.register("anthropic")
class AnthropicAsLLM(BaseAsLLM):
"""Anthropic chat model wrapper."""
@ -118,6 +161,7 @@ class XAIAsLLM(BaseAsLLM):
__all__ = [
"BaseAsLLM",
"OpenAIAsLLM",
"OrcaRouterAsLLM",
"AnthropicAsLLM",
"DashScopeAsLLM",
"DeepSeekAsLLM",

View file

@ -0,0 +1,40 @@
"""Tests for the OrcaRouter LLM provider."""
# pylint: disable=missing-function-docstring,missing-class-docstring,unused-argument
from reme.components.as_llm import OrcaRouterAsLLM, OrcaRouterCredential
from reme.components.component_registry import R, create_application_registry
from reme.enumeration import ComponentEnum
def test_orcarouter_registered_in_builtin_registry():
assert R.get(ComponentEnum.AS_LLM, "orcarouter") is OrcaRouterAsLLM
def test_application_registry_includes_orcarouter():
reg = create_application_registry()
assert reg.get(ComponentEnum.AS_LLM, "orcarouter") is OrcaRouterAsLLM
def test_orcarouter_credential_defaults_to_hosted_gateway():
credential = OrcaRouterCredential(api_key="sk-orca-test")
assert credential.base_url == "https://api.orcarouter.ai/v1"
def test_orcarouter_credential_empty_base_url_falls_back_to_gateway():
# The shared config passes ``base_url: ${LLM_BASE_URL:-}``, which yields an
# empty string when LLM_BASE_URL is unset.
credential = OrcaRouterCredential(api_key="sk-orca-test", base_url="")
assert credential.base_url == "https://api.orcarouter.ai/v1"
def test_orcarouter_credential_custom_base_url_kept():
credential = OrcaRouterCredential(
api_key="sk-orca-test",
base_url="https://selfhosted.example.com/v1",
)
assert credential.base_url == "https://selfhosted.example.com/v1"
def test_orcarouter_credential_reuses_openai_chat_model():
assert OrcaRouterCredential.get_chat_model_class().__name__ == "OpenAIChatModel"