Skip to content

Commit

Permalink
Merge pull request #57 from SylphAI-Inc/li
Browse files Browse the repository at this point in the history
Li
  • Loading branch information
liyin2015 authored Jun 29, 2024
2 parents ca0605c + fa73a97 commit 53c8e71
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 52 deletions.
10 changes: 7 additions & 3 deletions docs/source/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
--pst-color-logo: #2EB5EB;
--bs-gray-500:#adb5bd;

}

}
.theme-version {
display: none;
}
p {
font-size: 0.9em;
margin-bottom: 1.15rem;
}

html[data-theme=light] {
--pst-color-secondary: #3d3d3d; /*change the secondary color, header link to gray */
--pst-color-link-hover: #25262; /*change the side bar link color to black */
Expand All @@ -27,7 +31,7 @@ h1{
font-size: 2rem; /* make the h1 in the code smaller */
}
/* .bd-page-width {
max-width: 100%;
max-width: 100%;
} */

.sig-name {
Expand Down
16 changes: 6 additions & 10 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@
# sys.path.insert(0, dir[0])
# # print(dir[0])

import lightrag

import lightrag.components
import lightrag.core
import lightrag.eval
import lightrag.utils
import lightrag.tracing
import lightrag.optim

# -- Project information -----------------------------------------------------

Expand All @@ -55,13 +47,15 @@
"sphinx_design",
"sphinx_copybutton",
"nbsphinx",
"sphinx_search.extension"
"sphinx_search.extension",
# "myst_nb",
# "sphinx.builders.changes",
# 'recommonmark',
# 'myst_parser'
]

html_show_sphinx = False


# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
Expand Down Expand Up @@ -134,4 +128,6 @@


def setup(app):
app.add_css_file("css/custom.css") # Add custom CSS file to the Sphinx configuration
app.add_css_file(
"css/custom.css"
) # Add custom CSS file to the Sphinx configuration
7 changes: 4 additions & 3 deletions docs/source/developer_notes/base_data_class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,11 @@ The output will be:
}
}
question:
question: What is the capital of France?
metadata: {}
question: What is the capital of France?
metadata: {}
label: 1
metadata:
key: value
key: value
TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'})
True
Expand Down Expand Up @@ -569,6 +569,7 @@ You can simply do a bit customization to map the dataset's key to the field name

.. code-block:: python
@dataclass
class OutputFormat(DataClass):
thought: str = field(
metadata={
Expand Down
5 changes: 5 additions & 0 deletions docs/source/developer_notes/component.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Component
============
.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_

What you will learn?

1. What is ``Component`` and why is it designed this way?
Expand Down
8 changes: 7 additions & 1 deletion docs/source/developer_notes/db.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
Data & RAG
====================

The purpose of this note is to provide an overview on data, data modeling, and data storage in LLM applications along with how LightRAG works with data.
.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_


The purpose of this note is to provide an overview on data, data modeling, and data storage in LLM applications along with how LightRAG works with data.
We will conver:

* Data models on how to represent important data.
Expand Down
19 changes: 12 additions & 7 deletions docs/source/developer_notes/embedder.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Embedder
============
.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_

What you will learn?

1. What is ``Embedder`` and why is it designed this way?
Expand Down Expand Up @@ -62,10 +67,10 @@ We find the ``model_kwargs`` from the OpenAI API documentation. We setup `query`

**Visualize structure**: we use ``print(embedder)``. The output will be:

.. code-block::
.. code-block::
Embedder(
model_kwargs={'model': 'text-embedding-3-small', 'dimensions': 256, 'encoding_format': 'float'},
model_kwargs={'model': 'text-embedding-3-small', 'dimensions': 256, 'encoding_format': 'float'},
(model_client): OpenAIClient()
)
Expand Down Expand Up @@ -140,7 +145,7 @@ If we want to decreate the embedding dimension to only 256 to save memory, we ca
new_embedding = normalize_vector(new_embedding)
embedding.embedding = new_embedding
return output
def _extra_repr(self) -> str:
repr_str = f"old_dim={self.old_dim}, new_dim={self.new_dim}, normalize={self.normalize}"
return repr_str
Expand All @@ -159,10 +164,10 @@ Putting it all together, we can create a new embedder with the output processor.
The structure looks like:

.. code-block::
.. code-block::
Embedder(
model_kwargs={'model': 'thenlper/gte-base'},
model_kwargs={'model': 'thenlper/gte-base'},
(model_client): TransformersClient()
(output_processors): DecreaseEmbeddingDim(old_dim=768, new_dim=256, normalize=True)
)
Expand All @@ -188,7 +193,7 @@ The BatchEmbedder orchestrates the ``Embedder`` and handles the batching process
.. code-block:: python
from lightrag.core.embedder import BatchEmbedder
batch_embedder = BatchEmbedder(embedder=local_embedder, batch_size=100)
queries = [query] * 1000
Expand Down Expand Up @@ -216,4 +221,4 @@ The BatchEmbedder orchestrates the ``Embedder`` and handles the batching process
- :class:`core.types.Embedding`
- :class:`components.model_client.openai_client.OpenAIClient`
- :class:`components.model_client.transformers_client.TransformersClient`
- :class:`core.functional.normalize_vector`
- :class:`core.functional.normalize_vector`
7 changes: 6 additions & 1 deletion docs/source/developer_notes/evaluation.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
A Guideline on LLM Evaluation
====================================

As the saying goes, "You cannot improve what you cannot measure". This is especially true in the context of LLMs, which have become increasingly popular due to their impressive performance on a wide range of tasks. Evaluating LLMs and their applications is crucial in both research and production to understand their capabilities and limitations.
.. admonition:: Author
:class: highlight

`Meng Liu <https://github.com/mengliu1998>`_

"You cannot improve what you cannot measure". This is especially true in the context of LLMs, which have become increasingly popular due to their impressive performance on a wide range of tasks. Evaluating LLMs and their applications is crucial in both research and production to understand their capabilities and limitations.
Overall, such evaluation is a complex and multifaceted process. Below, we provide a guideline for evaluating LLMs and their applications, incorporating aspects outlined by *Chang et al.* [1]_:

* **What to evaluate**: the tasks and capabilities that LLMs are evaluated on.
Expand Down
18 changes: 12 additions & 6 deletions docs/source/developer_notes/generator.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
.. _generator:

Generator
Generator
=========

.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_

*The Center of it All*

Generator is the most essential functional component in LightRAG.
Generator is the most essential functional component in LightRAG.
It is a user-facing orchestration component with a simple and unified interface for LLM prediction.
It orchestrates the following components along with their required arguments:

Expand All @@ -20,7 +26,7 @@ GeneratorOutput
^^^^^^^^^^^^^^^
Different from all other components, we can not alway enforce LLM to output the right format.
We in particular created a :class:`core.types.GeneratorOutput` (a subclass of ``DataClass``) to store `data` (parsed response), `error` (error message if either the model inference SDKs fail or the output parsing fail) and `raw_response` (raw string response for reference) for any LLM predictions.
It is in developers' hands to process the output accordingly.
It is in developers' hands to process the output accordingly.

GeneratorInAction
^^^^^^^^^^^^^^^^^
Expand All @@ -38,7 +44,7 @@ In particular, we provide two tracing methods to help you develop and improve th
to lose track of the prompt changes when your current change actually makes the performance much worse.

We created a `GeneratorStateLogger` to handle the logging and saving into json files. To further simplify developers's process,
we provides a class decorator `trace_generator_states` where a single line of code can be added to any of your task component.
we provides a class decorator `trace_generator_states` where a single line of code can be added to any of your task component.
It will automatically track any attributes of type `Generator`.

.. code-block:: python
Expand All @@ -54,7 +60,7 @@ It will automatically track any attributes of type `Generator`.
self.generator_2 = Generator(...)
def call(...):
In default, a dir from the current working directory will be created to store the log files.
In default, a dir from the current working directory will be created to store the log files.
The project name in defaul is `SimpleQA` and the log file will be named as `generator_state_trace.json`
where both the `generator` and `generator_2` will be logged.
The structure of log directory is as follows:
Expand Down Expand Up @@ -147,7 +153,7 @@ Here is an example log file:
}
]
}
2. Trace all failed LLM predictions for further improvement.

Similarly, :class:`tracing.generator_call_logger.GeneratorCallLogger` is created to log generator call input arguments and output results.
Expand Down
24 changes: 15 additions & 9 deletions docs/source/developer_notes/model_client.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
ModelClient
============

.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_

What you will learn?

1. What is ``ModelClient`` and why is it designed this way?
Expand All @@ -23,7 +29,7 @@ Because so, by switching off ``ModelClient`` in a ``Generator`` or ``Embedder``

Model Inference SDKs
------------------------
With cloud API providers like OpenAI, Groq, Anthropic, it often comes with a `sync` and an `async` client via their SDKs.
With cloud API providers like OpenAI, Groq, Anthropic, it often comes with a `sync` and an `async` client via their SDKs.
For example:

.. code-block:: python
Expand All @@ -33,7 +39,7 @@ For example:
sync_client = OpenAI()
async_client = AsyncOpenAI()
# sync call using APIs
# sync call using APIs
response = sync_client.chat.completions.create(...)
For local models, such as using `huggingface transformers`, you need to create this model inference SDKs yourself.
Expand Down Expand Up @@ -141,7 +147,7 @@ This is how `OpenAIClient` implements these methods along with ``__init__`` meth
class OpenAIClient(ModelClient):
def __init__(self, api_key: Optional[str] = None):
super().__init__()
self._api_key = api_key
self.sync_client = self.init_sync_client()
Expand Down Expand Up @@ -175,7 +181,7 @@ This is how ``TransformerClient`` does the same thing:
}
def init_sync_client(self):
return TransformerEmbedder()
return TransformerEmbedder()
Second. we use `convert_inputs_to_api_kwargs` for subclass to convert LightRAG inputs into the `api_kwargs` (SDKs arguments).
Expand All @@ -202,7 +208,7 @@ This is how `OpenAIClient` implements this method:
model_kwargs: Dict = {},
model_type: ModelType = ModelType.UNDEFINED,
) -> Dict:
final_model_kwargs = model_kwargs.copy()
if model_type == ModelType.EMBEDDER:
if isinstance(input, str):
Expand Down Expand Up @@ -314,8 +320,8 @@ Here is an example to use ``OpenAIClient`` directly, first on LLM model:
prompt = f"User: {query}\n"
model_kwargs = {"model": "gpt-3.5-turbo", "temperature": 0.5, "max_tokens": 100}
api_kwargs = openai_client.convert_inputs_to_api_kwargs(input=prompt,
model_kwargs=model_kwargs,
api_kwargs = openai_client.convert_inputs_to_api_kwargs(input=prompt,
model_kwargs=model_kwargs,
model_type=model_type)
print(f"api_kwargs: {api_kwargs}")
Expand All @@ -325,10 +331,10 @@ Here is an example to use ``OpenAIClient`` directly, first on LLM model:
The output will be:

.. code-block::
.. code-block::
api_kwargs: {'model': 'gpt-3.5-turbo', 'temperature': 0.5, 'max_tokens': 100, 'messages': [{'role': 'system', 'content': 'User: What is the capital of France?\n'}]}
response_text: The capital of France is Paris.
response_text: The capital of France is Paris.
Then on Embedder model:

Expand Down
22 changes: 12 additions & 10 deletions docs/source/developer_notes/prompt.rst
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
Prompt
============
.. admonition:: Author
:class: highlight

`Li Yin <https://github.com/liyin2015>`_

We strick to maximize developers' control towards the final experience and performance, simplify the development process, and minimize the token consumption.

For the major chat models, we eventually will only send two messages to the model: the system message and the user message. The user message is simple,
often you have a message `{'role': 'user', 'content': 'Hello, how are you?'}`. The system message is more complex, it contains the task description, tools, examples, chat history, context, and
often you have a message `{'role': 'user', 'content': 'Hello, how are you?'}`. The system message is more complex, it contains the task description, tools, examples, chat history, context, and
intermediate step history from agents.

Prompt template
---------------------

Our `DEFAULT_LIGHTRAG_SYSTEM_PROMPT` templates the system prompt with 7 important sections. We leverage `jinjia2` template for **programmable prompt** right along with string.

The default template comes with 7 variables: `task_desc_str`, `output_format_str`, `tools_str`, `examples_str`, `chat_history_str`, `context_str`, and `steps_str`.
The default template comes with 7 variables: `task_desc_str`, `output_format_str`, `tools_str`, `examples_str`, `chat_history_str`, `context_str`, and `steps_str`.

A jinjia2 template will rendered with :ref:`Prompt<core-prompt_builder>` class. If some fields being empty, that section will be empty in the final prompt string.

Expand Down Expand Up @@ -54,7 +59,7 @@ A jinjia2 template will rendered with :ref:`Prompt<core-prompt_builder>` class.
{% endif %}
"""
Across our library, here our advanced features:
Across our library, here our advanced features:

- Various output formats where the `output_format_str` variable is used to pass the output format to the model.

Expand Down Expand Up @@ -108,19 +113,19 @@ Prompt and Special Tokens context
----------------------------------


Each section other than `task_desc_str` is encapulated in a special token. Different model can have different special tokens.
Each section other than `task_desc_str` is encapulated in a special token. Different model can have different special tokens.
Here is one example of `Llama3 Documentation <https://llama.meta.com/docs/model-cards-and-prompt-formats/meta-llama-3/>`_ prompts formatted with special tokens:

input string to the LLM model and minimize the token consumption.
input string to the LLM model and minimize the token consumption.
We enable advanced features without relying on API provider's prompt manipulation such as `OpenAI`'s tools or assistant APIs.

.. code-block::
.. code-block::
:linenos:
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are a helpful AI assistant for travel tips and recommendations<|eot_id|>
<|start_header_id|>user<|end_header_id|>
What can you help me with?<|eot_id|>
Expand Down Expand Up @@ -164,6 +169,3 @@ Output yaml or json format can lead to different performance. We have better luc

Resources:
1. `Jinja2`:



Loading

0 comments on commit 53c8e71

Please sign in to comment.