Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ result = query("Write a report about xxx.") # Your question here
#### LLM Configuration

<pre><code>config.set_provider_config("llm", "(LLMName)", "(Arguments dict)")</code></pre>
<p>The "LLMName" can be one of the following: ["DeepSeek", "OpenAI", "XAI", "SiliconFlow", "Aliyun", "PPIO", "TogetherAI", "Gemini", "Ollama", "Novita"]</p>
<p>The "LLMName" can be one of the following: ["DeepSeek", "OpenAI", "XAI", "SiliconFlow", "Aliyun", "PPIO", "TogetherAI", "Gemini", "Ollama", "Novita", "Jiekou.AI"]</p>
<p> The "Arguments dict" is a dictionary that contains the necessary arguments for the LLM class.</p>

<details>
Expand Down Expand Up @@ -173,6 +173,13 @@ result = query("Write a report about xxx.") # Your question here
<p> More details about PPIO: https://ppinfra.com/docs/get-started/quickstart.html?utm_source=github_deep-searcher </p>
</details>

<details>
<summary>Example (Claude Sonnet 4.5 from Jiekou.AI)</summary>
<p> Make sure you have prepared your Jiekou.AI API KEY as an env variable <code>JIEKOU_API_KEY</code>. You can create an API Key <a href="https://jiekou.ai/settings/key-management?utm_source=github_deep-searcher">here</a>. </p>
<pre><code>config.set_provider_config("llm", "JiekouAI", {"model": "claude-sonnet-4-5-20250929"})</code></pre>
<p> More details about Jiekou.AI: https://docs.jiekou.ai/docs/support/quickstart?utm_source=github_deep-searcher </p>
</details>

<details>
<summary>Example (Ollama)</summary>
<p> Follow <a href="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/jmorganca/ollama">these instructions</a> to set up and run a local Ollama instance:</p>
Expand Down Expand Up @@ -216,7 +223,7 @@ result = query("Write a report about xxx.") # Your question here

#### Embedding Model Configuration
<pre><code>config.set_provider_config("embedding", "(EmbeddingModelName)", "(Arguments dict)")</code></pre>
<p>The "EmbeddingModelName" can be one of the following: ["MilvusEmbedding", "OpenAIEmbedding", "VoyageEmbedding", "SiliconflowEmbedding", "PPIOEmbedding", "NovitaEmbedding"]</p>
<p>The "EmbeddingModelName" can be one of the following: ["MilvusEmbedding", "OpenAIEmbedding", "VoyageEmbedding", "SiliconflowEmbedding", "PPIOEmbedding", "NovitaEmbedding", "JiekouAIEmbedding"]</p>
<p> The "Arguments dict" is a dictionary that contains the necessary arguments for the embedding model class.</p>

<details>
Expand Down Expand Up @@ -308,6 +315,12 @@ result = query("Write a report about xxx.") # Your question here
<p> More details about PPIO: https://ppinfra.com/docs/get-started/quickstart.html?utm_source=github_deep-searcher </p>
</details>

<details>
<summary>Example (Jiekou.AI embedding)</summary>
<p> Make sure you have prepared your Jiekou.AI API KEY as an env variable <code>JIEKOU_API_KEY</code>.</p>
<pre><code>config.set_provider_config("embedding", "JiekouAIEmbedding", {"model": "qwen/qwen3-embedding-8b"})</code></pre>
<p> More details about Jiekou.AI: https://docs.jiekou.ai/docs/support/quickstart?utm_source=github_deep-searcher </p>
</details>

<details>
<summary>Example (FastEmbed embedding)</summary>
Expand Down Expand Up @@ -548,6 +561,7 @@ nest_asyncio.apply()
- [PPIO](https://ppinfra.com/model-api/product/llm-api?utm_source=github_deep-searcher) (`PPIO_API_KEY` env variable required)
- [Novita AI](https://novita.ai/docs/api-reference/model-apis-llm-create-embeddings?utm_source=github_deep-searcher&utm_medium=github_readme&utm_campaign=link) (`NOVITA_API_KEY` env variable required)
- [IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmembedding) (`WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` env variables required)
- [Jiekou.AI](https://jiekou.ai/?utm_source=github_deep-searcher) (`JIEKOU_API_KEY` env variable required)

### 🔹 LLM Support
- [OpenAI](https://platform.openai.com/docs/models) (`OPENAI_API_KEY` env variable required)
Expand All @@ -562,6 +576,7 @@ nest_asyncio.apply()
- [Ollama](https://ollama.com/)
- [Novita AI](https://novita.ai/docs/guides/introduction?utm_source=github_deep-searcher&utm_medium=github_readme&utm_campaign=link) (`NOVITA_API_KEY` env variable required)
- [IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmfm) (`WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` env variable required)
- [Jiekou.AI](https://jiekou.ai/?utm_source=github_deep-searcher) (`JIEKOU_API_KEY` env variable required)

### 🔹 Document Loader
- Local File
Expand Down
6 changes: 6 additions & 0 deletions deepsearcher/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ provide_settings:
## api_key: "sk_xxxxxx" # Uncomment to override the `PPIO_API_KEY` set in the environment variable
## base_url: ""

# provider: "Jiekou.AI"
# config:
# model: "claude-sonnet-4-5-20250929"
## api_key: "xxxx" # Uncomment to override the `JIEKOU_API_KEY` set in the environment variable
## base_url: ""

# provider: "TogetherAI"
# config:
# model: "deepseek-ai/DeepSeek-R1"
Expand Down
2 changes: 2 additions & 0 deletions deepsearcher/embedding/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .fastembed_embdding import FastEmbedEmbedding
from .gemini_embedding import GeminiEmbedding
from .glm_embedding import GLMEmbedding
from .jiekouai_embedding import JiekouAIEmbedding
from .milvus_embedding import MilvusEmbedding
from .novita_embedding import NovitaEmbedding
from .ollama_embedding import OllamaEmbedding
Expand All @@ -28,4 +29,5 @@
"NovitaEmbedding",
"SentenceTransformerEmbedding",
"WatsonXEmbedding",
"JiekouAIEmbedding",
]
131 changes: 131 additions & 0 deletions deepsearcher/embedding/jiekouai_embedding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
from typing import List, Union

import requests

from deepsearcher.embedding.base import BaseEmbedding

# TODO: Update with actual Jiekou.AI model dimensions when available
JIEKOUAI_MODEL_DIM_MAP = {
"qwen/qwen3-embedding-0.6b": 1024,
"qwen/qwen3-embedding-8b": 1024,
"baai/bge-m3": 1024,
}

JIEKOUAI_EMBEDDING_API = "https://api.jiekou.ai/openai/v1/embeddings"


class JiekouAIEmbedding(BaseEmbedding):
"""
Jiekou.AI embedding model implementation.

This class provides an interface to the Jiekou.AI embedding API, which offers
various embedding models for text processing.
"""

def __init__(self, model="qwen/qwen3-embedding-8b", batch_size=32, **kwargs):
"""
Initialize the Jiekou.AI embedding model.

Args:
model (str): The model identifier to use for embeddings. Default is "baai/bge-m3".
batch_size (int): Maximum number of texts to process in a single batch. Default is 32.
**kwargs: Additional keyword arguments.
- api_key (str, optional): The Jiekou.AI API key. If not provided,
it will be read from the JIEKOU_API_KEY environment variable.
- model_name (str, optional): Alternative way to specify the model.

Raises:
RuntimeError: If no API key is provided or found in environment variables.
"""
if "model_name" in kwargs and (not model or model == "qwen/qwen3-embedding-8b"):
model = kwargs.pop("model_name")
self.model = model

if "api_key" in kwargs:
api_key = kwargs.pop("api_key")
else:
api_key = os.getenv("JIEKOU_API_KEY")

if not api_key or len(api_key) == 0:
raise RuntimeError("api_key is required for JiekouAIEmbedding")
self.api_key = api_key
self.batch_size = batch_size

def embed_query(self, text: str) -> List[float]:
"""
Embed a single query text.

Args:
text (str): The query text to embed.

Returns:
List[float]: A list of floats representing the embedding vector.
"""
return self._embed_input(text)[0]

def embed_documents(self, texts: List[str]) -> List[List[float]]:
"""
Embed a list of document texts.

This method handles batching of document embeddings based on the configured
batch size to optimize API calls.

Args:
texts (List[str]): A list of document texts to embed.

Returns:
List[List[float]]: A list of embedding vectors, one for each input text.
"""
# batch embedding
if self.batch_size > 0:
if len(texts) > self.batch_size:
batch_texts = [
texts[i : i + self.batch_size] for i in range(0, len(texts), self.batch_size)
]
embeddings = []
for batch_text in batch_texts:
batch_embeddings = self._embed_input(batch_text)
embeddings.extend(batch_embeddings)
return embeddings
return self._embed_input(texts)
return [self.embed_query(text) for text in texts]

def _embed_input(self, input: Union[str, List[str]]) -> List[List[float]]:
"""
Internal method to handle the API call for embedding inputs.

Args:
input (Union[str, List[str]]): Either a single text string or a list of text strings to embed.

Returns:
List[List[float]]: A list of embedding vectors for the input(s).

Raises:
HTTPError: If the API request fails.
"""
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}

# Handle both single string and list of strings
input_list = input if isinstance(input, list) else [input]

payload = {"model": self.model, "input": input_list}

response = requests.request("POST", JIEKOUAI_EMBEDDING_API, json=payload, headers=headers)
response.raise_for_status()
result = response.json()["data"]
sorted_results = sorted(result, key=lambda x: x["index"])
return [res["embedding"] for res in sorted_results]

@property
def dimension(self) -> int:
"""
Get the dimensionality of the embeddings for the current model.

Returns:
int: The number of dimensions in the embedding vectors.
"""
return JIEKOUAI_MODEL_DIM_MAP[self.model]
2 changes: 2 additions & 0 deletions deepsearcher/llm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .deepseek import DeepSeek
from .gemini import Gemini
from .glm import GLM
from .jiekouai import JiekouAI
from .novita import Novita
from .ollama import Ollama
from .openai_llm import OpenAI
Expand Down Expand Up @@ -32,4 +33,5 @@
"Novita",
"Aliyun",
"WatsonX",
"JiekouAI",
]
61 changes: 61 additions & 0 deletions deepsearcher/llm/jiekouai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
from typing import Dict, List

from deepsearcher.llm.base import BaseLLM, ChatResponse


class JiekouAI(BaseLLM):
"""
Jiekou.AI language model implementation.

This class provides an interface to interact with language models
hosted on the Jiekou.AI platform.

Attributes:
model (str): The model identifier to use on Jiekou.AI platform.
client: The OpenAI-compatible client instance for Jiekou.AI API.
"""

def __init__(self, model: str = "claude-sonnet-4-5-20250929", **kwargs):
"""
Initialize a Jiekou.AI language model client.

Args:
model (str, optional): The model identifier to use. Defaults to "claude-sonnet-4-5-20250929".
**kwargs: Additional keyword arguments to pass to the OpenAI client.
- api_key: Jiekou.AI API key. If not provided, uses JIEKOU_API_KEY environment variable.
- base_url: Jiekou.AI API base URL. If not provided, defaults to "https://api.jiekou.ai/openai/v1".
"""
from openai import OpenAI as OpenAI_

self.model = model
if "api_key" in kwargs:
api_key = kwargs.pop("api_key")
else:
api_key = os.getenv("JIEKOU_API_KEY")
if "base_url" in kwargs:
base_url = kwargs.pop("base_url")
else:
base_url = "https://api.jiekou.ai/openai/v1"
self.client = OpenAI_(api_key=api_key, base_url=base_url, **kwargs)

def chat(self, messages: List[Dict]) -> ChatResponse:
"""
Send a chat message to the Jiekou.AI model and get a response.

Args:
messages (List[Dict]): A list of message dictionaries, typically in the format
[{"role": "system", "content": "..."},
{"role": "user", "content": "..."}]

Returns:
ChatResponse: An object containing the model's response and token usage information.
"""
completion = self.client.chat.completions.create(
model=self.model,
messages=messages,
)
return ChatResponse(
content=completion.choices[0].message.content,
total_tokens=completion.usage.total_tokens,
)
8 changes: 8 additions & 0 deletions docs/configuration/embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ config.set_provider_config("embedding", "(EmbeddingModelName)", "(Arguments dict
| **NovitaEmbedding** | Novita AI embedding | Cost-effective |
| **SentenceTransformerEmbedding** | Sentence Transfomer Embedding | Self-hosted option |
| **IBM watsonx.ai** | Various options | IBM's Enterprise AI platform |
| **JiekouAIEmbedding** | Jiekou.AI embedding | High quality, cost-effective |

## 🔍 Provider Examples

Expand Down Expand Up @@ -124,3 +125,10 @@ config.set_provider_config("embedding", "VoyageEmbedding", {"model": "voyage-3"}
config.set_provider_config("embedding", "WatsonXEmbedding", {"model": "ibm/slate-125m-english-rtrvr-v2"})
```
*Requires `pip install ibm-watsonx-ai`*

??? example "Jiekou.AI"

```python
config.set_provider_config("embedding", "JiekouAIEmbedding", {"model": "qwen/qwen3-embedding-8b"})
```
*Requires `JIEKOU_API_KEY` environment variable*
11 changes: 11 additions & 0 deletions docs/configuration/llm.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ config.set_provider_config("llm", "(LLMName)", "(Arguments dict)")
| **Bedrock** | Amazon Bedrock LLMs | anthropic.claude, ai21.j2 |
| **Novita** | Novita AI models | Various options |
| **IBM watsonx.ai** | IBM Enterprise AI platform | Various options |
| **Jiekou.AI** | Jiekou.AI models | Claude, OpenAI, Deepseek, Grok, Qwen, etc. |

## 🔍 Provider Examples

Expand Down Expand Up @@ -190,3 +191,13 @@ config.set_provider_config("llm", "WatsonX", {"model": "ibm/granite-3-3-8b-instr

More details about WatsonX: [https://www.ibm.com/products/watsonx-ai/foundation-models](https://www.ibm.com/products/watsonx-ai/foundation-models)
```

??? example "Jiekou.AI"

```python
config.set_provider_config("llm", "JiekouAI", {"model": "claude-sonnet-4-5-20250929"})
```
*Requires `JIEKOU_API_KEY` environment variable*

More details about Jiekou.AI: [https://docs.jiekou.ai/docs/support/quickstart](https://docs.jiekou.ai/docs/support/quickstart)

2 changes: 2 additions & 0 deletions docs/integrations/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Support for various embedding models to convert text into vector representations
| **[PPIO](https://ppinfra.com/model-api/product/llm-api)** | `PPIO_API_KEY` | Flexible cloud embeddings |
| **[Novita AI](https://novita.ai/docs/api-reference/model-apis-llm-create-embeddings)** | `NOVITA_API_KEY` | Rich model selection |
| **[IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmembedding)** | `WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` | IBM's Enterprise AI platform |
| **[Jiekou.AI](https://jiekou.ai/?utm_source=github_deep-searcher)** | `JIEKOU_API_KEY` | Jiekou.AI's embedding models |

## 🧠 Large Language Models {#llm-support}

Expand All @@ -44,6 +45,7 @@ Support for various large language models (LLMs) to process queries and generate
| **[Ollama](https://ollama.com/)** | None | Local LLM deployment |
| **[Novita AI](https://novita.ai/docs/guides/introduction)** | `NOVITA_API_KEY` | Diverse AI services |
| **[IBM watsonx.ai](https://www.ibm.com/products/watsonx-ai/foundation-models#ibmfm)** | `WATSONX_APIKEY`, `WATSONX_URL`, `WATSONX_PROJECT_ID` | IBM's Enterprise AI platform |
| **[Jiekou.AI](https://jiekou.ai/?utm_source=github_deep-searcher)** | `JIEKOU_API_KEY` | Various open-source and closed-source models |

## 📄 Document Loader {#document-loader}

Expand Down
3 changes: 3 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ SILICONFLOW_API_KEY=your_siliconflow_api_key_here
# PPIO API Key (required if using PPIO models)
PPIO_API_KEY=your_ppio_api_key_here

# Jiekou.AI API Key (required if using Jiekou.AI models)
JIEKOU_API_KEY=your_jiekouai_api_key_here

# Together AI API Key (required if using Together AI models)
TOGETHER_API_KEY=your_together_api_key_here

Expand Down
15 changes: 10 additions & 5 deletions examples/basic_example.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is not necessary, please keep this example file unchanged

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import os
import glob

from deepsearcher.offline_loading import load_from_local_files
from deepsearcher.online_query import query
Expand All @@ -11,6 +12,8 @@
current_dir = os.path.dirname(os.path.abspath(__file__))

config = Configuration() # Customize your config here
config.set_provider_config("llm", "JiekouAI", {"model": "claude-sonnet-4-5-20250929"})
config.set_provider_config("embedding", "JiekouAIEmbedding", {"model": "qwen/qwen3-embedding-8b"})
init_config(config=config)


Expand All @@ -23,13 +26,15 @@

# Hint: You can also load a single file, please execute it in the root directory of the deep searcher project
load_from_local_files(
paths_or_directory=os.path.join(current_dir, "data/WhatisMilvus.pdf"),
collection_name="milvus_docs",
collection_description="All Milvus Documents",
# force_new_collection=True, # If you want to drop origin collection and create a new collection every time, set force_new_collection to True
paths_or_directory='/Users/jason/Documents/work/PPLabs/Platform/deep-searcher/examples/data/car_company_data.pdf',
collection_name="car_company_data",
collection_description="car_company_data",
force_new_collection=True, # If you want to drop origin collection and create a new collection every time, set force_new_collection to True
)

question = "Write a report comparing Milvus with other vector databases."
question = """请从财务和宏观经济角度,对 A 股新能源汽车行业以及行业内 TOP5 车企的发展进行分析。在财务分析部分,需涵盖基本的财务关键指标。
在宏观经济分析部分,考虑宏观经济指标对行业的影响,对 A 股新能源汽车行业整体发展趋势进行总结,并基于财务和宏观经济分析,对 TOP5 新能源车企的未来发展潜力和竞争态势做出比较和预测,指出各车企的优势与挑战。请以专业、严谨的语言,结合具体数据进行分析阐述。
"""

_, _, consumed_token = query(question, max_iter=1)
print(f"Consumed tokens: {consumed_token}")
Loading