langroid 0.1.24__tar.gz → 0.1.26__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. {langroid-0.1.24 → langroid-0.1.26}/PKG-INFO +93 -68
  2. {langroid-0.1.24 → langroid-0.1.26}/README.md +92 -67
  3. {langroid-0.1.24 → langroid-0.1.26}/langroid/cachedb/redis_cachedb.py +6 -6
  4. {langroid-0.1.24 → langroid-0.1.26}/langroid/vector_store/qdrantdb.py +12 -10
  5. {langroid-0.1.24 → langroid-0.1.26}/pyproject.toml +1 -1
  6. langroid-0.1.26/setup.py +86 -0
  7. langroid-0.1.24/setup.py +0 -86
  8. {langroid-0.1.24 → langroid-0.1.26}/LICENSE +0 -0
  9. {langroid-0.1.24 → langroid-0.1.26}/langroid/__init__.py +0 -0
  10. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/__init__.py +0 -0
  11. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/base.py +0 -0
  12. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/chat_agent.py +0 -0
  13. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/chat_document.py +0 -0
  14. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/helpers.py +0 -0
  15. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/junk +0 -0
  16. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/special/__init__.py +0 -0
  17. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/special/doc_chat_agent.py +0 -0
  18. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/special/recipient_validator_agent.py +0 -0
  19. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/special/retriever_agent.py +0 -0
  20. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/task.py +0 -0
  21. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent/tool_message.py +0 -0
  22. {langroid-0.1.24 → langroid-0.1.26}/langroid/agent_config.py +0 -0
  23. {langroid-0.1.24 → langroid-0.1.26}/langroid/cachedb/__init__.py +0 -0
  24. {langroid-0.1.24 → langroid-0.1.26}/langroid/cachedb/base.py +0 -0
  25. {langroid-0.1.24 → langroid-0.1.26}/langroid/embedding_models/__init__.py +0 -0
  26. {langroid-0.1.24 → langroid-0.1.26}/langroid/embedding_models/base.py +0 -0
  27. {langroid-0.1.24 → langroid-0.1.26}/langroid/embedding_models/clustering.py +0 -0
  28. {langroid-0.1.24 → langroid-0.1.26}/langroid/embedding_models/models.py +0 -0
  29. {langroid-0.1.24 → langroid-0.1.26}/langroid/language_models/__init__.py +0 -0
  30. {langroid-0.1.24 → langroid-0.1.26}/langroid/language_models/base.py +0 -0
  31. {langroid-0.1.24 → langroid-0.1.26}/langroid/language_models/openai_gpt.py +0 -0
  32. {langroid-0.1.24 → langroid-0.1.26}/langroid/language_models/utils.py +0 -0
  33. {langroid-0.1.24 → langroid-0.1.26}/langroid/mytypes.py +0 -0
  34. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/__init__.py +0 -0
  35. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/agent_chats.py +0 -0
  36. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/code-parsing.md +0 -0
  37. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/code_parser.py +0 -0
  38. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/json.py +0 -0
  39. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/para_sentence_split.py +0 -0
  40. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/parser.py +0 -0
  41. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/pdf_parser.py +0 -0
  42. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/repo_loader.py +0 -0
  43. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/url_loader.py +0 -0
  44. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/url_loader_cookies.py +0 -0
  45. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/urls.py +0 -0
  46. {langroid-0.1.24 → langroid-0.1.26}/langroid/parsing/utils.py +0 -0
  47. {langroid-0.1.24 → langroid-0.1.26}/langroid/prompts/__init__.py +0 -0
  48. {langroid-0.1.24 → langroid-0.1.26}/langroid/prompts/dialog.py +0 -0
  49. {langroid-0.1.24 → langroid-0.1.26}/langroid/prompts/prompts_config.py +0 -0
  50. {langroid-0.1.24 → langroid-0.1.26}/langroid/prompts/templates.py +0 -0
  51. {langroid-0.1.24 → langroid-0.1.26}/langroid/prompts/transforms.py +0 -0
  52. {langroid-0.1.24 → langroid-0.1.26}/langroid/scripts/__init__.py +0 -0
  53. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/__init__.py +0 -0
  54. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/configuration.py +0 -0
  55. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/constants.py +0 -0
  56. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/docker.py +0 -0
  57. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/llms/__init__.py +0 -0
  58. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/llms/strings.py +0 -0
  59. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/logging.py +0 -0
  60. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/output/__init__.py +0 -0
  61. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/output/printing.py +0 -0
  62. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/system.py +0 -0
  63. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/web/__init__.py +0 -0
  64. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/web/login.py +0 -0
  65. {langroid-0.1.24 → langroid-0.1.26}/langroid/utils/web/selenium_login.py +0 -0
  66. {langroid-0.1.24 → langroid-0.1.26}/langroid/vector_store/__init__.py +0 -0
  67. {langroid-0.1.24 → langroid-0.1.26}/langroid/vector_store/base.py +0 -0
  68. {langroid-0.1.24 → langroid-0.1.26}/langroid/vector_store/chromadb.py +0 -0
  69. {langroid-0.1.24 → langroid-0.1.26}/langroid/vector_store/qdrant_cloud.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langroid
3
- Version: 0.1.24
3
+ Version: 0.1.26
4
4
  Summary: Harness LLMs with Multi-Agent Programming
5
5
  License: MIT
6
6
  Author: Prasad Chalasani
@@ -57,7 +57,7 @@ Requires-Dist: wget (>=3.2,<4.0)
57
57
  Description-Content-Type: text/markdown
58
58
 
59
59
  <div align="center">
60
- <img src="docs/assets/langroid-card-ossem-rust-1200x630.png" alt="Logo"
60
+ <img src="docs/assets/langroid-card-lambda-ossem-rust-1200-630.png" alt="Logo"
61
61
  width="400" align="center">
62
62
  </div>
63
63
 
@@ -75,47 +75,53 @@ Description-Content-Type: text/markdown
75
75
  <a target="_blank"
76
76
  href="https://langroid.github.io/langroid/" rel="dofollow">
77
77
  <strong>Explore the docs</strong></a>
78
- ·
78
+ &middot;
79
79
  <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">
80
80
  <strong>Examples Repo</strong></a>
81
- .
81
+ &middot;
82
82
  <a target="_blank" href="https://discord.gg/g3nAXCbZ" rel="dofollow">
83
83
  <strong>Discord</strong></a>
84
- .
84
+ &middot;
85
85
  <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">
86
86
  <strong>Contributing</strong></a>
87
87
 
88
88
  <br />
89
89
  </h3>
90
90
 
91
- `Langroid` is an intuitive, lightweight, transparent, extensible and principled
92
- Python framework to super-charge development of LLM-powered applications using Multi-Agent Programming.
93
- Inspired by the [Actor Framework](https://en.wikipedia.org/wiki/Actor_model),
94
- it is the first LLM-application framework that was explicitly
95
- designed with Agents as first-class citizens, and Multi-Agent Programming
96
- as the core design principle.
91
+ `Langroid` is an intuitive, lightweight, extensible and principled
92
+ Python framework to easily build LLM-powered applications.
93
+ You set up Agents, equip them with optional components (LLM,
94
+ vector-store and methods), assign them tasks, and have them
95
+ collaboratively solve a problem by exchanging messages.
96
+ This Multi-Agent paradigm is inspired by the
97
+ [Actor Framework](https://en.wikipedia.org/wiki/Actor_model)
98
+ (but you do not need to know anything about this!).
97
99
 
98
100
 
99
101
  # :rocket: Demo
100
-
101
- A `LeaseExtractor` agent is tasked with extracting structured information
102
- from a commercial lease document. The Agent's LLM generates questions that are
103
- answered by a `DocAgent` (its LLM) using Retrieval from a vector-database
104
- (into which the lease has been sharded + embedded).
105
- When it has all the information it needs, the `LeaseExtractor` agent's LLM
106
- presents the information in a structured format using a Function-call.
107
- You can run this script from the
108
- [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.
102
+ Suppose you want to extract structured information about the key terms
103
+ of a commercial lease document. You can easily do this with Langroid using a two-agent system,
104
+ as we show in the [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.
105
+ The demo showcases several features of Langroid:
106
+ - Multi-agent collaboration: `LeaseExtractor` is in charge of the task, and its LLM (GPT4) generates questions
107
+ to be answered by the `DocAgent`.
108
+ - Retrieval augmented question-answering: `DocAgent` LLM (GPT4) uses retrieval from a vector-store to
109
+ answer the `LeaseExtractor`'s questions.
110
+ - Function-calling (also known as tool/plugin): When it has all the information it
111
+ needs, the `LeaseExtractor` LLM presents the information in a structured
112
+ format using a Function-call.
113
+
114
+ Here is what it looks like in action:
109
115
 
110
116
  ![Demo](docs/assets/demos/lease-extractor-demo.gif)
111
117
 
112
118
 
113
119
  # :zap: Highlights
114
120
 
115
- - **Agents as first-class citizens:** The `Agent` class encapsulates LLM conversation state,
121
+ - **Agents as first-class citizens:** The [Agent](https://langroid.github.io/langroid/reference/agent/base/#langroid.agent.base.Agent) class encapsulates LLM conversation state,
116
122
  and optionally a vector-store and tools. Agents are a core abstraction in Langroid;
117
123
  Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.
118
- - **Tasks:** A Task class wraps an Agent, and gives the agent instructions (or roles, or goals),
124
+ - **Tasks:** A [Task](https://langroid.github.io/langroid/reference/agent/task/) class wraps an Agent, and gives the agent instructions (or roles, or goals),
119
125
  manages iteration over an Agent's responder methods,
120
126
  and orchestrates multi-agent interactions via hierarchical, recursive
121
127
  task-delegation. The `Task.run()` method has the same
@@ -166,34 +172,47 @@ Note that this will install `torch` and `sentence-transformers` libraries.
166
172
 
167
173
  ### Set up environment variables (API keys, etc)
168
174
 
169
- Copy the `.env-template` file to a new file `.env` and
170
- insert these secrets:
171
- - **OpenAI API** key (required): If you don't have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).
172
- - **Qdrant** Vector Store API Key (required for apps that need retrieval from
173
- documents): Sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
175
+ In the root of the repo, copy the `.env-template` file to a new file `.env`:
176
+ ```bash
177
+ cp .env-template .env
178
+ ```
179
+ Then insert your OpenAI API Key. If you don't have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).
180
+ Your `.env` file should look like this:
181
+
182
+ ```bash
183
+ OPENAI_API_KEY=your-key-here-without-quotes
184
+ ````
185
+
186
+ Currently only OpenAI models are supported. Others will be added later
187
+ (Pull Requests welcome!).
188
+
189
+ All of the below are optional and not strictly needed to run any of the examples.
190
+
191
+ - **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.
192
+ You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
193
+ If you skip setting up these, Langroid will use Qdrant in local-storage mode.
174
194
  Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported.
175
195
  We use the local-storage version of Chroma, so there is no need for an API key.
196
+ - **Redis** Password, host, port: This is optional, and only needed to cache LLM API responses
197
+ using Redis Cloud. Redis [offers](https://redis.com/try-free/) a free 30MB Redis account
198
+ which is more than sufficient to try out Langroid and even beyond.
199
+ If you don't set up these, Langroid will use a pure-python
200
+ Redis in-memory cache via the [Fakeredis](https://fakeredis.readthedocs.io/en/latest/) library.
176
201
  - **GitHub** Personal Access Token (required for apps that need to analyze git
177
202
  repos; token-based API calls are less rate-limited). See this
178
203
  [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).
179
- - **Redis** Password (optional, only needed to cache LLM API responses):
180
- Redis [offers](https://redis.com/try-free/) a free 30MB Redis account
181
- which is more than sufficient to try out Langroid and even beyond.
182
-
183
- ```bash
184
- cp .env-template .env
185
- # now edit the .env file, insert your secrets as above
186
- ```
187
- Your `.env` file should look like this:
204
+
205
+ If you add all of these optional variables, your `.env` file should look like this:
188
206
  ```bash
189
- OPENAI_API_KEY=<your key>
190
- GITHUB_ACCESS_TOKEN=<your token>
191
- REDIS_PASSWORD=<your password>
192
- QDRANT_API_KEY=<your key>
207
+ OPENAI_API_KEY=your-key-here-without-quotes
208
+ GITHUB_ACCESS_TOKEN=your-personal-access-token-no-quotes
209
+ REDIS_PASSWORD=your-redis-password-no-quotes
210
+ REDIS_HOST=your-redis-hostname-no-quotes
211
+ REDIS_PORT=your-redis-port-no-quotes
212
+ QDRANT_API_KEY=your-key
213
+ QDRANT_API_URL=https://your.url.here:6333 # note port number must be included
193
214
  ```
194
215
 
195
- Currently only OpenAI models are supported. Others will be added later
196
- (Pull Requests welcome!).
197
216
 
198
217
  ---
199
218
 
@@ -207,24 +226,21 @@ and they are **not** complete runnable examples! For that we encourage you to
207
226
  consult the [`langroid-examples`](https://github.com/langroid/langroid-examples)
208
227
  repository.
209
228
 
210
- :information_source: The examples below will only work with OpenAI GPT4 model,
211
- which is the default in Langroid. Switching to GPT3.5-Turbo is easy via a config
212
- flag, but results may be inferior.
229
+ :information_source: The various LLM prompts and instructions in Langroid
230
+ have been tested to work well with GPT4.
231
+ Switching to GPT3.5-Turbo is easy via a config flag
232
+ (e.g., `cfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT3_5_TURBO)`),
233
+ and may suffice for some applications, but in general you may see inferior results.
234
+
213
235
 
214
236
  :book: Also see the
215
237
  [`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)
216
- for a detailed tutorial.
238
+ for a detailed tutorial.
217
239
 
218
- - [Direct chat with LLM](#direct-llm)
219
- - [Simple Agent and Task](#agent-task)
220
- - [Three Communicating Agents](#three-agents)
221
- - [Agent with Tool/Function-calling](#agent-tool)
222
- - [Extract Structured Info with Tool/Function-calling](#agent-tool-structured)
223
- - [Retrieval-Augmented-Generation: Chat with Docs](#agent-rag)
224
-
225
- ---
240
+ Click to expand any of the code examples below:
226
241
 
227
- ## Direct interaction with OpenAI LLM <a name="direct-llm"></a>
242
+ <details>
243
+ <summary> <b> Direct interaction with OpenAI LLM </b> </summary>
228
244
 
229
245
  ```python
230
246
  from langroid.language_models.openai_gpt import (
@@ -243,10 +259,10 @@ messages = [
243
259
  response = mdl.chat(messages, max_tokens=200)
244
260
  print(response.message)
245
261
  ```
262
+ </details>
246
263
 
247
- ---
248
-
249
- ## Define an agent, set up a task, and run it <a name="agent-task"></a>
264
+ <details>
265
+ <summary> <b> Define an agent, set up a task, and run it </b> </summary>
250
266
 
251
267
  ```python
252
268
  from langroid.agent.chat_agent import ChatAgent, ChatAgentConfig
@@ -266,10 +282,12 @@ agent = ChatAgent(config)
266
282
  task = Task(agent, name="Bot")
267
283
  task.run() # ... a loop seeking response from LLM or User at each turn
268
284
  ```
285
+ </details>
269
286
 
270
- ---
287
+ <details>
288
+ <summary><b> Three communicating agents </b></summary>
271
289
 
272
- ## Three communicating agents <a name="three-agents"></a>
290
+ ```python
273
291
 
274
292
  A toy numbers game, where when given a number `n`:
275
293
  - `repeater_agent`'s LLM simply returns `n`,
@@ -329,9 +347,11 @@ and run the `repeater_task`, kicking it off with a number as input:
329
347
  repeater_task.add_sub_task([even_task, odd_task])
330
348
  repeater_task.run("3")
331
349
  ```
332
- ---
333
350
 
334
- ## Simple Tool/Function-calling example <a name="agent-tool"></a>
351
+ </details>
352
+
353
+ <details>
354
+ <summary><b> Simple Tool/Function-calling example </b></summary>
335
355
 
336
356
  Langroid leverages Pydantic to support OpenAI's
337
357
  [Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)
@@ -396,10 +416,10 @@ spy_game_agent.enable_message(ProbeTool)
396
416
  For a full working example see the
397
417
  [chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)
398
418
  script in the `langroid-examples` repo.
419
+ </details>
399
420
 
400
- ---
401
-
402
- ## Tool/Function-calling to extract structured information from text <a name="agent-tool-structured"></a>
421
+ <details>
422
+ <summary> <b>Tool/Function-calling to extract structured information from text </b> </summary>
403
423
 
404
424
  Suppose you want an agent to extract
405
425
  the key terms of a lease, from a lease document, as a nested JSON structure.
@@ -460,10 +480,10 @@ lease_extractor_agent.enable_message(LeaseMessage)
460
480
 
461
481
  See the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)
462
482
  script in the `langroid-examples` repo for a full working example.
483
+ </details>
463
484
 
464
- ---
465
-
466
- ## Chat with documents (file paths, URLs, etc) <a name="agent-docs"></a>
485
+ <details>
486
+ <summary><b> Chat with documents (file paths, URLs, etc) </b></summary>
467
487
 
468
488
  Langroid provides a specialized agent class `DocChatAgent` for this purpose.
469
489
  It incorporates document sharding, embedding, storage in a vector-DB,
@@ -509,9 +529,14 @@ task.run()
509
529
  See full working scripts in the
510
530
  [`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)
511
531
  folder of the `langroid-examples` repo.
532
+ </details>
512
533
 
513
534
  ---
514
535
 
536
+ # :heart: Thank you to our supporters!
537
+
538
+ [![Stargazers repo roster for @langroid/langroid](https://reporoster.com/stars/langroid/langroid)](https://github.com/langroid/langroid/stargazers)
539
+
515
540
  # Contributors
516
541
 
517
542
  - Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="docs/assets/langroid-card-ossem-rust-1200x630.png" alt="Logo"
2
+ <img src="docs/assets/langroid-card-lambda-ossem-rust-1200-630.png" alt="Logo"
3
3
  width="400" align="center">
4
4
  </div>
5
5
 
@@ -17,47 +17,53 @@
17
17
  <a target="_blank"
18
18
  href="https://langroid.github.io/langroid/" rel="dofollow">
19
19
  <strong>Explore the docs</strong></a>
20
- ·
20
+ &middot;
21
21
  <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">
22
22
  <strong>Examples Repo</strong></a>
23
- .
23
+ &middot;
24
24
  <a target="_blank" href="https://discord.gg/g3nAXCbZ" rel="dofollow">
25
25
  <strong>Discord</strong></a>
26
- .
26
+ &middot;
27
27
  <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">
28
28
  <strong>Contributing</strong></a>
29
29
 
30
30
  <br />
31
31
  </h3>
32
32
 
33
- `Langroid` is an intuitive, lightweight, transparent, extensible and principled
34
- Python framework to super-charge development of LLM-powered applications using Multi-Agent Programming.
35
- Inspired by the [Actor Framework](https://en.wikipedia.org/wiki/Actor_model),
36
- it is the first LLM-application framework that was explicitly
37
- designed with Agents as first-class citizens, and Multi-Agent Programming
38
- as the core design principle.
33
+ `Langroid` is an intuitive, lightweight, extensible and principled
34
+ Python framework to easily build LLM-powered applications.
35
+ You set up Agents, equip them with optional components (LLM,
36
+ vector-store and methods), assign them tasks, and have them
37
+ collaboratively solve a problem by exchanging messages.
38
+ This Multi-Agent paradigm is inspired by the
39
+ [Actor Framework](https://en.wikipedia.org/wiki/Actor_model)
40
+ (but you do not need to know anything about this!).
39
41
 
40
42
 
41
43
  # :rocket: Demo
42
-
43
- A `LeaseExtractor` agent is tasked with extracting structured information
44
- from a commercial lease document. The Agent's LLM generates questions that are
45
- answered by a `DocAgent` (its LLM) using Retrieval from a vector-database
46
- (into which the lease has been sharded + embedded).
47
- When it has all the information it needs, the `LeaseExtractor` agent's LLM
48
- presents the information in a structured format using a Function-call.
49
- You can run this script from the
50
- [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.
44
+ Suppose you want to extract structured information about the key terms
45
+ of a commercial lease document. You can easily do this with Langroid using a two-agent system,
46
+ as we show in the [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.
47
+ The demo showcases several features of Langroid:
48
+ - Multi-agent collaboration: `LeaseExtractor` is in charge of the task, and its LLM (GPT4) generates questions
49
+ to be answered by the `DocAgent`.
50
+ - Retrieval augmented question-answering: `DocAgent` LLM (GPT4) uses retrieval from a vector-store to
51
+ answer the `LeaseExtractor`'s questions.
52
+ - Function-calling (also known as tool/plugin): When it has all the information it
53
+ needs, the `LeaseExtractor` LLM presents the information in a structured
54
+ format using a Function-call.
55
+
56
+ Here is what it looks like in action:
51
57
 
52
58
  ![Demo](docs/assets/demos/lease-extractor-demo.gif)
53
59
 
54
60
 
55
61
  # :zap: Highlights
56
62
 
57
- - **Agents as first-class citizens:** The `Agent` class encapsulates LLM conversation state,
63
+ - **Agents as first-class citizens:** The [Agent](https://langroid.github.io/langroid/reference/agent/base/#langroid.agent.base.Agent) class encapsulates LLM conversation state,
58
64
  and optionally a vector-store and tools. Agents are a core abstraction in Langroid;
59
65
  Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.
60
- - **Tasks:** A Task class wraps an Agent, and gives the agent instructions (or roles, or goals),
66
+ - **Tasks:** A [Task](https://langroid.github.io/langroid/reference/agent/task/) class wraps an Agent, and gives the agent instructions (or roles, or goals),
61
67
  manages iteration over an Agent's responder methods,
62
68
  and orchestrates multi-agent interactions via hierarchical, recursive
63
69
  task-delegation. The `Task.run()` method has the same
@@ -108,34 +114,47 @@ Note that this will install `torch` and `sentence-transformers` libraries.
108
114
 
109
115
  ### Set up environment variables (API keys, etc)
110
116
 
111
- Copy the `.env-template` file to a new file `.env` and
112
- insert these secrets:
113
- - **OpenAI API** key (required): If you don't have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).
114
- - **Qdrant** Vector Store API Key (required for apps that need retrieval from
115
- documents): Sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
117
+ In the root of the repo, copy the `.env-template` file to a new file `.env`:
118
+ ```bash
119
+ cp .env-template .env
120
+ ```
121
+ Then insert your OpenAI API Key. If you don't have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).
122
+ Your `.env` file should look like this:
123
+
124
+ ```bash
125
+ OPENAI_API_KEY=your-key-here-without-quotes
126
+ ````
127
+
128
+ Currently only OpenAI models are supported. Others will be added later
129
+ (Pull Requests welcome!).
130
+
131
+ All of the below are optional and not strictly needed to run any of the examples.
132
+
133
+ - **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.
134
+ You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).
135
+ If you skip setting up these, Langroid will use Qdrant in local-storage mode.
116
136
  Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported.
117
137
  We use the local-storage version of Chroma, so there is no need for an API key.
138
+ - **Redis** Password, host, port: This is optional, and only needed to cache LLM API responses
139
+ using Redis Cloud. Redis [offers](https://redis.com/try-free/) a free 30MB Redis account
140
+ which is more than sufficient to try out Langroid and even beyond.
141
+ If you don't set up these, Langroid will use a pure-python
142
+ Redis in-memory cache via the [Fakeredis](https://fakeredis.readthedocs.io/en/latest/) library.
118
143
  - **GitHub** Personal Access Token (required for apps that need to analyze git
119
144
  repos; token-based API calls are less rate-limited). See this
120
145
  [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).
121
- - **Redis** Password (optional, only needed to cache LLM API responses):
122
- Redis [offers](https://redis.com/try-free/) a free 30MB Redis account
123
- which is more than sufficient to try out Langroid and even beyond.
124
-
125
- ```bash
126
- cp .env-template .env
127
- # now edit the .env file, insert your secrets as above
128
- ```
129
- Your `.env` file should look like this:
146
+
147
+ If you add all of these optional variables, your `.env` file should look like this:
130
148
  ```bash
131
- OPENAI_API_KEY=<your key>
132
- GITHUB_ACCESS_TOKEN=<your token>
133
- REDIS_PASSWORD=<your password>
134
- QDRANT_API_KEY=<your key>
149
+ OPENAI_API_KEY=your-key-here-without-quotes
150
+ GITHUB_ACCESS_TOKEN=your-personal-access-token-no-quotes
151
+ REDIS_PASSWORD=your-redis-password-no-quotes
152
+ REDIS_HOST=your-redis-hostname-no-quotes
153
+ REDIS_PORT=your-redis-port-no-quotes
154
+ QDRANT_API_KEY=your-key
155
+ QDRANT_API_URL=https://your.url.here:6333 # note port number must be included
135
156
  ```
136
157
 
137
- Currently only OpenAI models are supported. Others will be added later
138
- (Pull Requests welcome!).
139
158
 
140
159
  ---
141
160
 
@@ -149,24 +168,21 @@ and they are **not** complete runnable examples! For that we encourage you to
149
168
  consult the [`langroid-examples`](https://github.com/langroid/langroid-examples)
150
169
  repository.
151
170
 
152
- :information_source: The examples below will only work with OpenAI GPT4 model,
153
- which is the default in Langroid. Switching to GPT3.5-Turbo is easy via a config
154
- flag, but results may be inferior.
171
+ :information_source: The various LLM prompts and instructions in Langroid
172
+ have been tested to work well with GPT4.
173
+ Switching to GPT3.5-Turbo is easy via a config flag
174
+ (e.g., `cfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT3_5_TURBO)`),
175
+ and may suffice for some applications, but in general you may see inferior results.
176
+
155
177
 
156
178
  :book: Also see the
157
179
  [`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)
158
- for a detailed tutorial.
180
+ for a detailed tutorial.
159
181
 
160
- - [Direct chat with LLM](#direct-llm)
161
- - [Simple Agent and Task](#agent-task)
162
- - [Three Communicating Agents](#three-agents)
163
- - [Agent with Tool/Function-calling](#agent-tool)
164
- - [Extract Structured Info with Tool/Function-calling](#agent-tool-structured)
165
- - [Retrieval-Augmented-Generation: Chat with Docs](#agent-rag)
166
-
167
- ---
182
+ Click to expand any of the code examples below:
168
183
 
169
- ## Direct interaction with OpenAI LLM <a name="direct-llm"></a>
184
+ <details>
185
+ <summary> <b> Direct interaction with OpenAI LLM </b> </summary>
170
186
 
171
187
  ```python
172
188
  from langroid.language_models.openai_gpt import (
@@ -185,10 +201,10 @@ messages = [
185
201
  response = mdl.chat(messages, max_tokens=200)
186
202
  print(response.message)
187
203
  ```
204
+ </details>
188
205
 
189
- ---
190
-
191
- ## Define an agent, set up a task, and run it <a name="agent-task"></a>
206
+ <details>
207
+ <summary> <b> Define an agent, set up a task, and run it </b> </summary>
192
208
 
193
209
  ```python
194
210
  from langroid.agent.chat_agent import ChatAgent, ChatAgentConfig
@@ -208,10 +224,12 @@ agent = ChatAgent(config)
208
224
  task = Task(agent, name="Bot")
209
225
  task.run() # ... a loop seeking response from LLM or User at each turn
210
226
  ```
227
+ </details>
211
228
 
212
- ---
229
+ <details>
230
+ <summary><b> Three communicating agents </b></summary>
213
231
 
214
- ## Three communicating agents <a name="three-agents"></a>
232
+ ```python
215
233
 
216
234
  A toy numbers game, where when given a number `n`:
217
235
  - `repeater_agent`'s LLM simply returns `n`,
@@ -271,9 +289,11 @@ and run the `repeater_task`, kicking it off with a number as input:
271
289
  repeater_task.add_sub_task([even_task, odd_task])
272
290
  repeater_task.run("3")
273
291
  ```
274
- ---
275
292
 
276
- ## Simple Tool/Function-calling example <a name="agent-tool"></a>
293
+ </details>
294
+
295
+ <details>
296
+ <summary><b> Simple Tool/Function-calling example </b></summary>
277
297
 
278
298
  Langroid leverages Pydantic to support OpenAI's
279
299
  [Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)
@@ -338,10 +358,10 @@ spy_game_agent.enable_message(ProbeTool)
338
358
  For a full working example see the
339
359
  [chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)
340
360
  script in the `langroid-examples` repo.
361
+ </details>
341
362
 
342
- ---
343
-
344
- ## Tool/Function-calling to extract structured information from text <a name="agent-tool-structured"></a>
363
+ <details>
364
+ <summary> <b>Tool/Function-calling to extract structured information from text </b> </summary>
345
365
 
346
366
  Suppose you want an agent to extract
347
367
  the key terms of a lease, from a lease document, as a nested JSON structure.
@@ -402,10 +422,10 @@ lease_extractor_agent.enable_message(LeaseMessage)
402
422
 
403
423
  See the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)
404
424
  script in the `langroid-examples` repo for a full working example.
425
+ </details>
405
426
 
406
- ---
407
-
408
- ## Chat with documents (file paths, URLs, etc) <a name="agent-docs"></a>
427
+ <details>
428
+ <summary><b> Chat with documents (file paths, URLs, etc) </b></summary>
409
429
 
410
430
  Langroid provides a specialized agent class `DocChatAgent` for this purpose.
411
431
  It incorporates document sharding, embedding, storage in a vector-DB,
@@ -451,9 +471,14 @@ task.run()
451
471
  See full working scripts in the
452
472
  [`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)
453
473
  folder of the `langroid-examples` repo.
474
+ </details>
454
475
 
455
476
  ---
456
477
 
478
+ # :heart: Thank you to our supporters!
479
+
480
+ [![Stargazers repo roster for @langroid/langroid](https://reporoster.com/stars/langroid/langroid)](https://github.com/langroid/langroid/stargazers)
481
+
457
482
  # Contributors
458
483
 
459
484
  - Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)
@@ -17,8 +17,6 @@ class RedisCacheConfig(BaseModel):
17
17
  """Configuration model for RedisCache."""
18
18
 
19
19
  fake: bool = False
20
- hostname: str = "redis-11524.c251.east-us-mz.azure.cloud.redislabs.com"
21
- port: int = 11524
22
20
 
23
21
 
24
22
  class RedisCache(CacheDB):
@@ -38,16 +36,18 @@ class RedisCache(CacheDB):
38
36
  self.client = fakeredis.FakeStrictRedis() # type: ignore
39
37
  else:
40
38
  redis_password = os.getenv("REDIS_PASSWORD")
41
- if redis_password is None:
39
+ redis_host = os.getenv("REDIS_HOST")
40
+ redis_port = os.getenv("REDIS_PORT")
41
+ if None in [redis_password, redis_host, redis_port]:
42
42
  logger.warning(
43
- """REDIS_PASSWORD not set in .env file,
43
+ """REDIS_PASSWORD, REDIS_HOST, REDIS_PORT not set in .env file,
44
44
  using fake redis client"""
45
45
  )
46
46
  self.client = fakeredis.FakeStrictRedis() # type: ignore
47
47
  else:
48
48
  self.client = redis.Redis( # type: ignore
49
- host=self.config.hostname,
50
- port=self.config.port,
49
+ host=redis_host,
50
+ port=redis_port,
51
51
  password=redis_password,
52
52
  )
53
53
 
@@ -29,7 +29,6 @@ logger = logging.getLogger(__name__)
29
29
  class QdrantDBConfig(VectorStoreConfig):
30
30
  type: str = "qdrant"
31
31
  cloud: bool = True
32
- url = "https://644cabc3-4141-4734-91f2-0cc3176514d4.us-east-1-0.aws.cloud.qdrant.io:6333"
33
32
 
34
33
  collection_name: str | None = None
35
34
  storage_path: str = ".qdrant/data"
@@ -49,17 +48,20 @@ class QdrantDB(VectorStore):
49
48
  self.host = config.host
50
49
  self.port = config.port
51
50
  load_dotenv()
51
+ key = os.getenv("QDRANT_API_KEY")
52
+ url = os.getenv("QDRANT_API_URL")
53
+ if config.cloud and None in [key, url]:
54
+ logger.warning(
55
+ f"""QDRANT_API_KEY, QDRANT_API_URL env variable must be set to use
56
+ QdrantDB in cloud mode. Please set these values
57
+ in your .env file.
58
+ Switching to local storage at {config.storage_path}
59
+ """
60
+ )
61
+ config.cloud = False
52
62
  if config.cloud:
53
- key = os.getenv("QDRANT_API_KEY")
54
- if key is None or key == "":
55
- raise ValueError(
56
- """QDRANT_API_KEY env variable must be set to use
57
- QdrantDB in cloud mode. Please set the QDRANT_API_KEY value
58
- in your .env file.
59
- """
60
- )
61
63
  self.client = QdrantClient(
62
- url=config.url,
64
+ url=url,
63
65
  api_key=key,
64
66
  timeout=config.timeout,
65
67
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "langroid"
3
- version = "0.1.24"
3
+ version = "0.1.26"
4
4
  description = "Harness LLMs with Multi-Agent Programming"
5
5
  authors = ["Prasad Chalasani <pchalasani@gmail.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1,86 @@
1
+ # -*- coding: utf-8 -*-
2
+ from setuptools import setup
3
+
4
+ packages = \
5
+ ['langroid',
6
+ 'langroid.agent',
7
+ 'langroid.agent.special',
8
+ 'langroid.cachedb',
9
+ 'langroid.embedding_models',
10
+ 'langroid.language_models',
11
+ 'langroid.parsing',
12
+ 'langroid.prompts',
13
+ 'langroid.scripts',
14
+ 'langroid.utils',
15
+ 'langroid.utils.llms',
16
+ 'langroid.utils.output',
17
+ 'langroid.utils.web',
18
+ 'langroid.vector_store']
19
+
20
+ package_data = \
21
+ {'': ['*']}
22
+
23
+ install_requires = \
24
+ ['autopep8>=2.0.2,<3.0.0',
25
+ 'black[jupyter]>=23.3.0,<24.0.0',
26
+ 'bs4>=0.0.1,<0.0.2',
27
+ 'chromadb>=0.3.21,<0.4.0',
28
+ 'colorlog>=6.7.0,<7.0.0',
29
+ 'faker>=18.9.0,<19.0.0',
30
+ 'fakeredis>=2.12.1,<3.0.0',
31
+ 'fire>=0.5.0,<0.6.0',
32
+ 'flake8>=6.0.0,<7.0.0',
33
+ 'halo>=0.0.31,<0.0.32',
34
+ 'mkdocs-awesome-pages-plugin>=2.8.0,<3.0.0',
35
+ 'mkdocs-gen-files>=0.4.0,<0.5.0',
36
+ 'mkdocs-jupyter>=0.24.1,<0.25.0',
37
+ 'mkdocs-literate-nav>=0.6.0,<0.7.0',
38
+ 'mkdocs-material>=9.1.5,<10.0.0',
39
+ 'mkdocs-section-index>=0.3.5,<0.4.0',
40
+ 'mkdocs>=1.4.2,<2.0.0',
41
+ 'mkdocstrings[python]>=0.21.2,<0.22.0',
42
+ 'mypy>=1.2.0,<2.0.0',
43
+ 'nltk>=3.8.1,<4.0.0',
44
+ 'openai>=0.27.5,<0.28.0',
45
+ 'pre-commit>=3.3.2,<4.0.0',
46
+ 'pydantic==1.10.11',
47
+ 'pygithub>=1.58.1,<2.0.0',
48
+ 'pygments>=2.15.1,<3.0.0',
49
+ 'pyparsing>=3.0.9,<4.0.0',
50
+ 'pypdf>=3.12.2,<4.0.0',
51
+ 'python-dotenv>=1.0.0,<2.0.0',
52
+ 'qdrant-client>=1.3.1,<2.0.0',
53
+ 'redis>=4.5.5,<5.0.0',
54
+ 'requests-oauthlib>=1.3.1,<2.0.0',
55
+ 'requests>=2.31.0,<3.0.0',
56
+ 'rich>=13.3.4,<14.0.0',
57
+ 'ruff>=0.0.270,<0.0.271',
58
+ 'tiktoken>=0.3.3,<0.4.0',
59
+ 'trafilatura>=1.5.0,<2.0.0',
60
+ 'typer>=0.7.0,<0.8.0',
61
+ 'types-redis>=4.5.5.2,<5.0.0.0',
62
+ 'types-requests>=2.31.0.1,<3.0.0.0',
63
+ 'wget>=3.2,<4.0']
64
+
65
+ extras_require = \
66
+ {'hf-embeddings': ['sentence-transformers==2.2.2', 'torch==2.0.0']}
67
+
68
+ setup_kwargs = {
69
+ 'name': 'langroid',
70
+ 'version': '0.1.26',
71
+ 'description': 'Harness LLMs with Multi-Agent Programming',
72
+ 'long_description': '<div align="center">\n <img src="docs/assets/langroid-card-lambda-ossem-rust-1200-630.png" alt="Logo" \n width="400" align="center">\n</div>\n\n<div align="center">\n\n[![Pytest](https://github.com/langroid/langroid/actions/workflows/pytest.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/pytest.yml)\n[![Lint](https://github.com/langroid/langroid/actions/workflows/validate.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/validate.yml)\n[![Docs](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml)\n[![Static Badge](https://img.shields.io/badge/Documentation-blue?link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F&link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F)](https://langroid.github.io/langroid)\n[![Static Badge](https://img.shields.io/badge/Discord-Orange?link=https%3A%2F%2Fdiscord.gg%2Fg3nAXCbZ&link=https%3A%2F%2Fdiscord.gg%2Fg3nAXCbZ)](https://discord.gg/g3nAXCbZ)\n\n</div>\n\n<h3 align="center">\n <a target="_blank" \n href="https://langroid.github.io/langroid/" rel="dofollow">\n <strong>Explore the docs</strong></a>\n &middot;\n <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">\n <strong>Examples Repo</strong></a>\n &middot;\n <a target="_blank" href="https://discord.gg/g3nAXCbZ" rel="dofollow">\n <strong>Discord</strong></a>\n &middot;\n <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">\n <strong>Contributing</strong></a>\n\n <br />\n</h3>\n\n`Langroid` is an intuitive, lightweight, extensible and principled\nPython framework to easily build LLM-powered applications. \nYou set up Agents, equip them with optional components (LLM, \nvector-store and methods), assign them tasks, and have them \ncollaboratively solve a problem by exchanging messages. \nThis Multi-Agent paradigm is inspired by the\n[Actor Framework](https://en.wikipedia.org/wiki/Actor_model)\n(but you do not need to know anything about this!).\n\n\n# :rocket: Demo\nSuppose you want to extract structured information about the key terms \nof a commercial lease document. You can easily do this with Langroid using a two-agent system,\nas we show in the [langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.\nThe demo showcases several features of Langroid:\n- Multi-agent collaboration: `LeaseExtractor` is in charge of the task, and its LLM (GPT4) generates questions \nto be answered by the `DocAgent`.\n- Retrieval augmented question-answering: `DocAgent` LLM (GPT4) uses retrieval from a vector-store to \nanswer the `LeaseExtractor`\'s questions.\n- Function-calling (also known as tool/plugin): When it has all the information it \nneeds, the `LeaseExtractor` LLM presents the information in a structured \nformat using a Function-call. \n\nHere is what it looks like in action:\n\n![Demo](docs/assets/demos/lease-extractor-demo.gif)\n\n\n# :zap: Highlights\n\n- **Agents as first-class citizens:** The [Agent](https://langroid.github.io/langroid/reference/agent/base/#langroid.agent.base.Agent) class encapsulates LLM conversation state,\n and optionally a vector-store and tools. Agents are a core abstraction in Langroid;\n Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.\n- **Tasks:** A [Task](https://langroid.github.io/langroid/reference/agent/task/) class wraps an Agent, and gives the agent instructions (or roles, or goals), \n manages iteration over an Agent\'s responder methods, \n and orchestrates multi-agent interactions via hierarchical, recursive\n task-delegation. The `Task.run()` method has the same \n type-signature as an Agent\'s responder\'s methods, and this is key to how \n a task of an agent can delegate to other sub-tasks: from the point of view of a Task,\n sub-tasks are simply additional responders, to be used in a round-robin fashion \n after the agent\'s own responders.\n- **Modularity, Reusabilily, Loose coupling:** The `Agent` and `Task` abstractions allow users to design\n Agents with specific skills, wrap them in Tasks, and combine tasks in a flexible way.\n- **LLM Support**: Langroid supports OpenAI LLMs including GPT-3.5-Turbo,\n GPT-4-0613\n- **Caching of LLM prompts, responses:** Langroid uses [Redis](https://redis.com/try-free/) for caching.\n- **Vector-stores**: [Qdrant](https://qdrant.tech/) and [Chroma](https://www.trychroma.com/) are currently supported.\n Vector stores allow for Retrieval-Augmented-Generation (RAG).\n- **Grounding and source-citation:** Access to external documents via vector-stores \n allows for grounding and source-citation.\n- **Observability, Logging, Lineage:** Langroid generates detailed logs of multi-agent interactions and\n maintains provenance/lineage of messages, so that you can trace back\n the origin of a message.\n- **Tools/Plugins/Function-calling**: Langroid supports OpenAI\'s recently\n released [function calling](https://platform.openai.com/docs/guides/gpt/function-calling)\n feature. In addition, Langroid has its own native equivalent, which we\n call **tools** (also known as "plugins" in other contexts). Function\n calling and tools have the same developer-facing interface, implemented\n using [Pydantic](https://docs.pydantic.dev/latest/),\n which makes it very easy to define tools/functions and enable agents\n to use them. Benefits of using Pydantic are that you never have to write\n complex JSON specs for function calling, and when the LLM\n hallucinates malformed JSON, the Pydantic error message is sent back to\n the LLM so it can fix it!\n\n--- \n\n# :gear: Installation and Setup\n\n### Install `langroid` \nUse `pip` to install `langroid` (from PyPi) to your virtual environment:\n```bash\npip install langroid\n```\nThe core Langroid package lets you use OpenAI Embeddings models via their API. \nIf you instead want to use the `all-MiniLM-L6-v2` embeddings model\nfrom from HuggingFace, install Langroid like this:\n```bash\npip install langroid[hf-embeddings]\n```\nNote that this will install `torch` and `sentence-transformers` libraries.\n\n### Set up environment variables (API keys, etc)\n\nIn the root of the repo, copy the `.env-template` file to a new file `.env`: \n```bash\ncp .env-template .env\n```\nThen insert your OpenAI API Key. If you don\'t have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).\nYour `.env` file should look like this:\n\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\n````\n\nCurrently only OpenAI models are supported. Others will be added later\n(Pull Requests welcome!).\n\nAll of the below are optional and not strictly needed to run any of the examples.\n\n- **Qdrant** Vector Store API Key, URL. This is only required if you want to use Qdrant cloud.\n You can sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).\n If you skip setting up these, Langroid will use Qdrant in local-storage mode.\n Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported. \n We use the local-storage version of Chroma, so there is no need for an API key.\n- **Redis** Password, host, port: This is optional, and only needed to cache LLM API responses\n using Redis Cloud. Redis [offers](https://redis.com/try-free/) a free 30MB Redis account\n which is more than sufficient to try out Langroid and even beyond.\n If you don\'t set up these, Langroid will use a pure-python \n Redis in-memory cache via the [Fakeredis](https://fakeredis.readthedocs.io/en/latest/) library.\n- **GitHub** Personal Access Token (required for apps that need to analyze git\n repos; token-based API calls are less rate-limited). See this\n [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).\n\nIf you add all of these optional variables, your `.env` file should look like this:\n```bash\nOPENAI_API_KEY=your-key-here-without-quotes\nGITHUB_ACCESS_TOKEN=your-personal-access-token-no-quotes\nREDIS_PASSWORD=your-redis-password-no-quotes\nREDIS_HOST=your-redis-hostname-no-quotes\nREDIS_PORT=your-redis-port-no-quotes\nQDRANT_API_KEY=your-key\nQDRANT_API_URL=https://your.url.here:6333 # note port number must be included\n```\n\n\n---\n\n# :tada: Usage Examples\n\nThese are quick teasers to give a glimpse of what you can do with Langroid\nand how your code would look. \n\n:warning: The code snippets below are intended to give a flavor of the code\nand they are **not** complete runnable examples! For that we encourage you to \nconsult the [`langroid-examples`](https://github.com/langroid/langroid-examples) \nrepository.\n\n:information_source: The various LLM prompts and instructions in Langroid\nhave been tested to work well with GPT4.\nSwitching to GPT3.5-Turbo is easy via a config flag\n(e.g., `cfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT3_5_TURBO)`),\nand may suffice for some applications, but in general you may see inferior results.\n\n\n:book: Also see the\n[`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)\nfor a detailed tutorial.\n\nClick to expand any of the code examples below:\n\n<details>\n<summary> <b> Direct interaction with OpenAI LLM </b> </summary>\n\n```python\nfrom langroid.language_models.openai_gpt import ( \n OpenAIGPTConfig, OpenAIChatModel, OpenAIGPT,\n)\nfrom langroid.language_models.base import LLMMessage, Role\n\ncfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT4)\n\nmdl = OpenAIGPT(cfg)\n\nmessages = [\n LLMMessage(content="You are a helpful assistant", role=Role.SYSTEM), \n LLMMessage(content="What is the capital of Ontario?", role=Role.USER),\n]\nresponse = mdl.chat(messages, max_tokens=200)\nprint(response.message)\n```\n</details>\n\n<details>\n<summary> <b> Define an agent, set up a task, and run it </b> </summary>\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None, # no vector store\n)\nagent = ChatAgent(config)\n# get response from agent\'s LLM, and put this in an interactive loop...\n# answer = agent.llm_response("What is the capital of Ontario?")\n # ... OR instead, set up a task (which has a built-in loop) and run it\ntask = Task(agent, name="Bot") \ntask.run() # ... a loop seeking response from LLM or User at each turn\n```\n</details>\n\n<details>\n<summary><b> Three communicating agents </b></summary>\n\n```python\n\nA toy numbers game, where when given a number `n`:\n- `repeater_agent`\'s LLM simply returns `n`,\n- `even_agent`\'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"\n- `odd_agent`\'s LLM returns `3*n+1` if `n` is odd, else says "DO-NOT-KNOW"\n\nFirst define the 3 agents, and set up their tasks with instructions:\n\n```python\nfrom langroid.utils.constants import NO_ANSWER\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb = None,\n)\nrepeater_agent = ChatAgent(config)\nrepeater_task = Task(\n repeater_agent,\n name = "Repeater",\n system_message="""\n Your job is to repeat whatever number you receive.\n """,\n llm_delegate=True, # LLM takes charge of task\n single_round=False, \n)\neven_agent = ChatAgent(config)\neven_task = Task(\n even_agent,\n name = "EvenHandler",\n system_message=f"""\n You will be given a number. \n If it is even, divide by 2 and say the result, nothing else.\n If it is odd, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n\nodd_agent = ChatAgent(config)\nodd_task = Task(\n odd_agent,\n name = "OddHandler",\n system_message=f"""\n You will be given a number n. \n If it is odd, return (n*3+1), say nothing else. \n If it is even, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n```\nThen add the `even_task` and `odd_task` as sub-tasks of `repeater_task`, \nand run the `repeater_task`, kicking it off with a number as input:\n```python\nrepeater_task.add_sub_task([even_task, odd_task])\nrepeater_task.run("3")\n```\n\n</details>\n\n<details>\n<summary><b> Simple Tool/Function-calling example </b></summary>\n\nLangroid leverages Pydantic to support OpenAI\'s\n[Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)\nas well as its own native tools. The benefits are that you don\'t have to write\nany JSON to specify the schema, and also if the LLM hallucinates a malformed\ntool syntax, Langroid sends the Pydantic validation error (suitiably sanitized) \nto the LLM so it can fix it!\n\nSimple example: Say the agent has a secret list of numbers, \nand we want the LLM to find the smallest number in the list. \nWe want to give the LLM a `probe` tool/function which takes a\nsingle number `n` as argument. The tool handler method in the agent\nreturns how many numbers in its list are at most `n`.\n\nFirst define the tool using Langroid\'s `ToolMessage` class:\n\n\n```python\nfrom langroid.agent.tool_message import ToolMessage\nclass ProbeTool(ToolMessage):\n request: str = "probe" # specifies which agent method handles this tool\n purpose: str = """\n To find how many numbers in my list are less than or equal to \n the <number> you specify.\n """ # description used to instruct the LLM on when/how to use the tool\n number: int # required argument to the tool\n```\n\nThen define a `SpyGameAgent` as a subclass of `ChatAgent`, \nwith a method `probe` that handles this tool:\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nclass SpyGameAgent(ChatAgent):\n def __init__(self, config: ChatAgentConfig):\n super().__init__(config)\n self.numbers = [3, 4, 8, 11, 15, 25, 40, 80, 90]\n\n def probe(self, msg: ProbeTool) -> str:\n # return how many numbers in self.numbers are less or equal to msg.number\n return str(len([n for n in self.numbers if n <= msg.number]))\n```\n\nWe then instantiate the agent and enable it to use and respond to the tool:\n\n```python\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nspy_game_agent = SpyGameAgent(\n ChatAgentConfig(\n name="Spy",\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None,\n use_tools=False, # don\'t use Langroid native tool\n use_functions_api=True, # use OpenAI function-call API\n )\n)\nspy_game_agent.enable_message(ProbeTool)\n```\n\nFor a full working example see the\n[chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)\nscript in the `langroid-examples` repo.\n</details>\n\n<details>\n<summary> <b>Tool/Function-calling to extract structured information from text </b> </summary>\n\nSuppose you want an agent to extract \nthe key terms of a lease, from a lease document, as a nested JSON structure.\nFirst define the desired structure via Pydantic models:\n\n```python\nfrom pydantic import BaseModel\nclass LeasePeriod(BaseModel):\n start_date: str\n end_date: str\n\n\nclass LeaseFinancials(BaseModel):\n monthly_rent: str\n deposit: str\n\nclass Lease(BaseModel):\n period: LeasePeriod\n financials: LeaseFinancials\n address: str\n```\n\nThen define the `LeaseMessage` tool as a subclass of Langroid\'s `ToolMessage`.\nNote the tool has a required argument `terms` of type `Lease`:\n\n```python\nclass LeaseMessage(ToolMessage):\n request: str = "lease_info"\n purpose: str = """\n Collect information about a Commercial Lease.\n """\n terms: Lease\n```\n\nThen define a `LeaseExtractorAgent` with a method `lease_info` that handles this tool,\ninstantiate the agent, and enable it to use and respond to this tool:\n\n```python\nclass LeaseExtractorAgent(ChatAgent):\n def lease_info(self, message: LeaseMessage) -> str:\n print(\n f"""\n DONE! Successfully extracted Lease Info:\n {message.terms}\n """\n )\n return json.dumps(message.terms.dict())\n \nlease_extractor_agent = LeaseExtractorAgent(\n ChatAgentConfig(\n llm=OpenAIGPTConfig(),\n use_functions_api=False,\n use_tools=True,\n )\n)\nlease_extractor_agent.enable_message(LeaseMessage)\n```\n\nSee the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)\nscript in the `langroid-examples` repo for a full working example.\n</details>\n\n<details>\n<summary><b> Chat with documents (file paths, URLs, etc) </b></summary>\n\nLangroid provides a specialized agent class `DocChatAgent` for this purpose.\nIt incorporates document sharding, embedding, storage in a vector-DB, \nand retrieval-augmented query-answer generation.\nUsing this class to chat with a collection of documents is easy.\nFirst create a `DocChatAgentConfig` instance, with a \n`doc_paths` field that specifies the documents to chat with.\n\n```python\nfrom langroid.agent.doc_chat_agent import DocChatAgentConfig\nconfig = DocChatAgentConfig(\n doc_paths = [\n "https://en.wikipedia.org/wiki/Language_model",\n "https://en.wikipedia.org/wiki/N-gram_language_model",\n "/path/to/my/notes-on-language-models.txt",\n ]\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=VectorStoreConfig(\n type="qdrant",\n ),\n)\n```\n\nThen instantiate the `DocChatAgent`, ingest the docs into the vector-store:\n\n```python\nagent = DocChatAgent(config)\nagent.ingest()\n```\nThen we can either ask the agent one-off questions,\n```python\nagent.chat("What is a language model?")\n```\nor wrap it in a `Task` and run an interactive loop with the user:\n```python\nfrom langroid.task import Task\ntask = Task(agent)\ntask.run()\n```\n\nSee full working scripts in the \n[`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)\nfolder of the `langroid-examples` repo.\n</details>\n\n---\n\n# :heart: Thank you to our supporters!\n\n[![Stargazers repo roster for @langroid/langroid](https://reporoster.com/stars/langroid/langroid)](https://github.com/langroid/langroid/stargazers)\n\n# Contributors\n\n- Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)\n- Somesh Jha (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)\n- Mohannad Alhanahnah (Research Associate, U Wisc at Madison)\n- Ashish Hooda (IIT BTech/CS; PhD Candidate, U Wisc at Madison)\n\n',
73
+ 'author': 'Prasad Chalasani',
74
+ 'author_email': 'pchalasani@gmail.com',
75
+ 'maintainer': 'None',
76
+ 'maintainer_email': 'None',
77
+ 'url': 'None',
78
+ 'packages': packages,
79
+ 'package_data': package_data,
80
+ 'install_requires': install_requires,
81
+ 'extras_require': extras_require,
82
+ 'python_requires': '>=3.8.1,<3.12',
83
+ }
84
+
85
+
86
+ setup(**setup_kwargs)
langroid-0.1.24/setup.py DELETED
@@ -1,86 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from setuptools import setup
3
-
4
- packages = \
5
- ['langroid',
6
- 'langroid.agent',
7
- 'langroid.agent.special',
8
- 'langroid.cachedb',
9
- 'langroid.embedding_models',
10
- 'langroid.language_models',
11
- 'langroid.parsing',
12
- 'langroid.prompts',
13
- 'langroid.scripts',
14
- 'langroid.utils',
15
- 'langroid.utils.llms',
16
- 'langroid.utils.output',
17
- 'langroid.utils.web',
18
- 'langroid.vector_store']
19
-
20
- package_data = \
21
- {'': ['*']}
22
-
23
- install_requires = \
24
- ['autopep8>=2.0.2,<3.0.0',
25
- 'black[jupyter]>=23.3.0,<24.0.0',
26
- 'bs4>=0.0.1,<0.0.2',
27
- 'chromadb>=0.3.21,<0.4.0',
28
- 'colorlog>=6.7.0,<7.0.0',
29
- 'faker>=18.9.0,<19.0.0',
30
- 'fakeredis>=2.12.1,<3.0.0',
31
- 'fire>=0.5.0,<0.6.0',
32
- 'flake8>=6.0.0,<7.0.0',
33
- 'halo>=0.0.31,<0.0.32',
34
- 'mkdocs-awesome-pages-plugin>=2.8.0,<3.0.0',
35
- 'mkdocs-gen-files>=0.4.0,<0.5.0',
36
- 'mkdocs-jupyter>=0.24.1,<0.25.0',
37
- 'mkdocs-literate-nav>=0.6.0,<0.7.0',
38
- 'mkdocs-material>=9.1.5,<10.0.0',
39
- 'mkdocs-section-index>=0.3.5,<0.4.0',
40
- 'mkdocs>=1.4.2,<2.0.0',
41
- 'mkdocstrings[python]>=0.21.2,<0.22.0',
42
- 'mypy>=1.2.0,<2.0.0',
43
- 'nltk>=3.8.1,<4.0.0',
44
- 'openai>=0.27.5,<0.28.0',
45
- 'pre-commit>=3.3.2,<4.0.0',
46
- 'pydantic==1.10.11',
47
- 'pygithub>=1.58.1,<2.0.0',
48
- 'pygments>=2.15.1,<3.0.0',
49
- 'pyparsing>=3.0.9,<4.0.0',
50
- 'pypdf>=3.12.2,<4.0.0',
51
- 'python-dotenv>=1.0.0,<2.0.0',
52
- 'qdrant-client>=1.3.1,<2.0.0',
53
- 'redis>=4.5.5,<5.0.0',
54
- 'requests-oauthlib>=1.3.1,<2.0.0',
55
- 'requests>=2.31.0,<3.0.0',
56
- 'rich>=13.3.4,<14.0.0',
57
- 'ruff>=0.0.270,<0.0.271',
58
- 'tiktoken>=0.3.3,<0.4.0',
59
- 'trafilatura>=1.5.0,<2.0.0',
60
- 'typer>=0.7.0,<0.8.0',
61
- 'types-redis>=4.5.5.2,<5.0.0.0',
62
- 'types-requests>=2.31.0.1,<3.0.0.0',
63
- 'wget>=3.2,<4.0']
64
-
65
- extras_require = \
66
- {'hf-embeddings': ['sentence-transformers==2.2.2', 'torch==2.0.0']}
67
-
68
- setup_kwargs = {
69
- 'name': 'langroid',
70
- 'version': '0.1.24',
71
- 'description': 'Harness LLMs with Multi-Agent Programming',
72
- 'long_description': '<div align="center">\n <img src="docs/assets/langroid-card-ossem-rust-1200x630.png" alt="Logo" \n width="400" align="center">\n</div>\n\n<div align="center">\n\n[![Pytest](https://github.com/langroid/langroid/actions/workflows/pytest.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/pytest.yml)\n[![Lint](https://github.com/langroid/langroid/actions/workflows/validate.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/validate.yml)\n[![Docs](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml/badge.svg)](https://github.com/langroid/langroid/actions/workflows/mkdocs-deploy.yml)\n[![Static Badge](https://img.shields.io/badge/Documentation-blue?link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F&link=https%3A%2F%2Flangroid.github.io%2Flangroid%2F)](https://langroid.github.io/langroid)\n[![Static Badge](https://img.shields.io/badge/Discord-Orange?link=https%3A%2F%2Fdiscord.gg%2Fg3nAXCbZ&link=https%3A%2F%2Fdiscord.gg%2Fg3nAXCbZ)](https://discord.gg/g3nAXCbZ)\n\n</div>\n\n<h3 align="center">\n <a target="_blank" \n href="https://langroid.github.io/langroid/" rel="dofollow">\n <strong>Explore the docs</strong></a>\n ·\n <a target="_blank" href="https://github.com/langroid/langroid-examples" rel="dofollow">\n <strong>Examples Repo</strong></a>\n .\n <a target="_blank" href="https://discord.gg/g3nAXCbZ" rel="dofollow">\n <strong>Discord</strong></a>\n .\n <a target="_blank" href="./CONTRIBUTING.md" rel="dofollow">\n <strong>Contributing</strong></a>\n\n <br />\n</h3>\n\n`Langroid` is an intuitive, lightweight, transparent, extensible and principled\nPython framework to super-charge development of LLM-powered applications using Multi-Agent Programming.\nInspired by the [Actor Framework](https://en.wikipedia.org/wiki/Actor_model), \nit is the first LLM-application framework that was explicitly\ndesigned with Agents as first-class citizens, and Multi-Agent Programming\nas the core design principle.\n\n\n# :rocket: Demo\n\nA `LeaseExtractor` agent is tasked with extracting structured information\nfrom a commercial lease document. The Agent\'s LLM generates questions that are \nanswered by a `DocAgent` (its LLM) using Retrieval from a vector-database\n(into which the lease has been sharded + embedded).\nWhen it has all the information it needs, the `LeaseExtractor` agent\'s LLM\npresents the information in a structured format using a Function-call.\nYou can run this script from the \n[langroid-examples](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py) repo.\n\n![Demo](docs/assets/demos/lease-extractor-demo.gif)\n\n\n# :zap: Highlights\n\n- **Agents as first-class citizens:** The `Agent` class encapsulates LLM conversation state,\n and optionally a vector-store and tools. Agents are a core abstraction in Langroid;\n Agents act as _message transformers_, and by default provide 3 _responder_ methods, one corresponding to each entity: LLM, Agent, User.\n- **Tasks:** A Task class wraps an Agent, and gives the agent instructions (or roles, or goals), \n manages iteration over an Agent\'s responder methods, \n and orchestrates multi-agent interactions via hierarchical, recursive\n task-delegation. The `Task.run()` method has the same \n type-signature as an Agent\'s responder\'s methods, and this is key to how \n a task of an agent can delegate to other sub-tasks: from the point of view of a Task,\n sub-tasks are simply additional responders, to be used in a round-robin fashion \n after the agent\'s own responders.\n- **Modularity, Reusabilily, Loose coupling:** The `Agent` and `Task` abstractions allow users to design\n Agents with specific skills, wrap them in Tasks, and combine tasks in a flexible way.\n- **LLM Support**: Langroid supports OpenAI LLMs including GPT-3.5-Turbo,\n GPT-4-0613\n- **Caching of LLM prompts, responses:** Langroid uses [Redis](https://redis.com/try-free/) for caching.\n- **Vector-stores**: [Qdrant](https://qdrant.tech/) and [Chroma](https://www.trychroma.com/) are currently supported.\n Vector stores allow for Retrieval-Augmented-Generation (RAG).\n- **Grounding and source-citation:** Access to external documents via vector-stores \n allows for grounding and source-citation.\n- **Observability, Logging, Lineage:** Langroid generates detailed logs of multi-agent interactions and\n maintains provenance/lineage of messages, so that you can trace back\n the origin of a message.\n- **Tools/Plugins/Function-calling**: Langroid supports OpenAI\'s recently\n released [function calling](https://platform.openai.com/docs/guides/gpt/function-calling)\n feature. In addition, Langroid has its own native equivalent, which we\n call **tools** (also known as "plugins" in other contexts). Function\n calling and tools have the same developer-facing interface, implemented\n using [Pydantic](https://docs.pydantic.dev/latest/),\n which makes it very easy to define tools/functions and enable agents\n to use them. Benefits of using Pydantic are that you never have to write\n complex JSON specs for function calling, and when the LLM\n hallucinates malformed JSON, the Pydantic error message is sent back to\n the LLM so it can fix it!\n\n--- \n\n# :gear: Installation and Setup\n\n### Install `langroid` \nUse `pip` to install `langroid` (from PyPi) to your virtual environment:\n```bash\npip install langroid\n```\nThe core Langroid package lets you use OpenAI Embeddings models via their API. \nIf you instead want to use the `all-MiniLM-L6-v2` embeddings model\nfrom from HuggingFace, install Langroid like this:\n```bash\npip install langroid[hf-embeddings]\n```\nNote that this will install `torch` and `sentence-transformers` libraries.\n\n### Set up environment variables (API keys, etc)\n\nCopy the `.env-template` file to a new file `.env` and \ninsert these secrets:\n- **OpenAI API** key (required): If you don\'t have one, see [this OpenAI Page](https://help.openai.com/en/collections/3675940-getting-started-with-openai-api).\n- **Qdrant** Vector Store API Key (required for apps that need retrieval from\n documents): Sign up for a free 1GB account at [Qdrant cloud](https://cloud.qdrant.io).\n Alternatively [Chroma](https://docs.trychroma.com/) is also currently supported. \n We use the local-storage version of Chroma, so there is no need for an API key.\n- **GitHub** Personal Access Token (required for apps that need to analyze git\n repos; token-based API calls are less rate-limited). See this\n [GitHub page](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).\n- **Redis** Password (optional, only needed to cache LLM API responses):\n Redis [offers](https://redis.com/try-free/) a free 30MB Redis account\n which is more than sufficient to try out Langroid and even beyond.\n \n```bash\ncp .env-template .env\n# now edit the .env file, insert your secrets as above\n``` \nYour `.env` file should look like this:\n```bash\nOPENAI_API_KEY=<your key>\nGITHUB_ACCESS_TOKEN=<your token>\nREDIS_PASSWORD=<your password>\nQDRANT_API_KEY=<your key>\n```\n\nCurrently only OpenAI models are supported. Others will be added later\n(Pull Requests welcome!).\n\n---\n\n# :tada: Usage Examples\n\nThese are quick teasers to give a glimpse of what you can do with Langroid\nand how your code would look. \n\n:warning: The code snippets below are intended to give a flavor of the code\nand they are **not** complete runnable examples! For that we encourage you to \nconsult the [`langroid-examples`](https://github.com/langroid/langroid-examples) \nrepository.\n\n:information_source: The examples below will only work with OpenAI GPT4 model,\nwhich is the default in Langroid. Switching to GPT3.5-Turbo is easy via a config \nflag, but results may be inferior.\n\n:book: Also see the\n[`Getting Started Guide`](https://langroid.github.io/langroid/quick-start/)\nfor a detailed tutorial. \n\n- [Direct chat with LLM](#direct-llm)\n- [Simple Agent and Task](#agent-task)\n- [Three Communicating Agents](#three-agents)\n- [Agent with Tool/Function-calling](#agent-tool)\n- [Extract Structured Info with Tool/Function-calling](#agent-tool-structured)\n- [Retrieval-Augmented-Generation: Chat with Docs](#agent-rag)\n\n---\n\n## Direct interaction with OpenAI LLM <a name="direct-llm"></a>\n\n```python\nfrom langroid.language_models.openai_gpt import ( \n OpenAIGPTConfig, OpenAIChatModel, OpenAIGPT,\n)\nfrom langroid.language_models.base import LLMMessage, Role\n\ncfg = OpenAIGPTConfig(chat_model=OpenAIChatModel.GPT4)\n\nmdl = OpenAIGPT(cfg)\n\nmessages = [\n LLMMessage(content="You are a helpful assistant", role=Role.SYSTEM), \n LLMMessage(content="What is the capital of Ontario?", role=Role.USER),\n]\nresponse = mdl.chat(messages, max_tokens=200)\nprint(response.message)\n```\n\n---\n\n## Define an agent, set up a task, and run it <a name="agent-task"></a>\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\n\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None, # no vector store\n)\nagent = ChatAgent(config)\n# get response from agent\'s LLM, and put this in an interactive loop...\n# answer = agent.llm_response("What is the capital of Ontario?")\n # ... OR instead, set up a task (which has a built-in loop) and run it\ntask = Task(agent, name="Bot") \ntask.run() # ... a loop seeking response from LLM or User at each turn\n```\n\n---\n\n## Three communicating agents <a name="three-agents"></a>\n\nA toy numbers game, where when given a number `n`:\n- `repeater_agent`\'s LLM simply returns `n`,\n- `even_agent`\'s LLM returns `n/2` if `n` is even, else says "DO-NOT-KNOW"\n- `odd_agent`\'s LLM returns `3*n+1` if `n` is odd, else says "DO-NOT-KNOW"\n\nFirst define the 3 agents, and set up their tasks with instructions:\n\n```python\nfrom langroid.utils.constants import NO_ANSWER\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nfrom langroid.agent.task import Task\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nconfig = ChatAgentConfig(\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb = None,\n)\nrepeater_agent = ChatAgent(config)\nrepeater_task = Task(\n repeater_agent,\n name = "Repeater",\n system_message="""\n Your job is to repeat whatever number you receive.\n """,\n llm_delegate=True, # LLM takes charge of task\n single_round=False, \n)\neven_agent = ChatAgent(config)\neven_task = Task(\n even_agent,\n name = "EvenHandler",\n system_message=f"""\n You will be given a number. \n If it is even, divide by 2 and say the result, nothing else.\n If it is odd, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n\nodd_agent = ChatAgent(config)\nodd_task = Task(\n odd_agent,\n name = "OddHandler",\n system_message=f"""\n You will be given a number n. \n If it is odd, return (n*3+1), say nothing else. \n If it is even, say {NO_ANSWER}\n """,\n single_round=True, # task done after 1 step() with valid response\n)\n```\nThen add the `even_task` and `odd_task` as sub-tasks of `repeater_task`, \nand run the `repeater_task`, kicking it off with a number as input:\n```python\nrepeater_task.add_sub_task([even_task, odd_task])\nrepeater_task.run("3")\n```\n---\n\n## Simple Tool/Function-calling example <a name="agent-tool"></a>\n\nLangroid leverages Pydantic to support OpenAI\'s\n[Function-calling API](https://platform.openai.com/docs/guides/gpt/function-calling)\nas well as its own native tools. The benefits are that you don\'t have to write\nany JSON to specify the schema, and also if the LLM hallucinates a malformed\ntool syntax, Langroid sends the Pydantic validation error (suitiably sanitized) \nto the LLM so it can fix it!\n\nSimple example: Say the agent has a secret list of numbers, \nand we want the LLM to find the smallest number in the list. \nWe want to give the LLM a `probe` tool/function which takes a\nsingle number `n` as argument. The tool handler method in the agent\nreturns how many numbers in its list are at most `n`.\n\nFirst define the tool using Langroid\'s `ToolMessage` class:\n\n\n```python\nfrom langroid.agent.tool_message import ToolMessage\nclass ProbeTool(ToolMessage):\n request: str = "probe" # specifies which agent method handles this tool\n purpose: str = """\n To find how many numbers in my list are less than or equal to \n the <number> you specify.\n """ # description used to instruct the LLM on when/how to use the tool\n number: int # required argument to the tool\n```\n\nThen define a `SpyGameAgent` as a subclass of `ChatAgent`, \nwith a method `probe` that handles this tool:\n\n```python\nfrom langroid.agent.chat_agent import ChatAgent, ChatAgentConfig\nclass SpyGameAgent(ChatAgent):\n def __init__(self, config: ChatAgentConfig):\n super().__init__(config)\n self.numbers = [3, 4, 8, 11, 15, 25, 40, 80, 90]\n\n def probe(self, msg: ProbeTool) -> str:\n # return how many numbers in self.numbers are less or equal to msg.number\n return str(len([n for n in self.numbers if n <= msg.number]))\n```\n\nWe then instantiate the agent and enable it to use and respond to the tool:\n\n```python\nfrom langroid.language_models.openai_gpt import OpenAIChatModel, OpenAIGPTConfig\nspy_game_agent = SpyGameAgent(\n ChatAgentConfig(\n name="Spy",\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=None,\n use_tools=False, # don\'t use Langroid native tool\n use_functions_api=True, # use OpenAI function-call API\n )\n)\nspy_game_agent.enable_message(ProbeTool)\n```\n\nFor a full working example see the\n[chat-agent-tool.py](https://github.com/langroid/langroid-examples/blob/main/examples/quick-start/chat-agent-tool.py)\nscript in the `langroid-examples` repo.\n\n---\n\n## Tool/Function-calling to extract structured information from text <a name="agent-tool-structured"></a>\n\nSuppose you want an agent to extract \nthe key terms of a lease, from a lease document, as a nested JSON structure.\nFirst define the desired structure via Pydantic models:\n\n```python\nfrom pydantic import BaseModel\nclass LeasePeriod(BaseModel):\n start_date: str\n end_date: str\n\n\nclass LeaseFinancials(BaseModel):\n monthly_rent: str\n deposit: str\n\nclass Lease(BaseModel):\n period: LeasePeriod\n financials: LeaseFinancials\n address: str\n```\n\nThen define the `LeaseMessage` tool as a subclass of Langroid\'s `ToolMessage`.\nNote the tool has a required argument `terms` of type `Lease`:\n\n```python\nclass LeaseMessage(ToolMessage):\n request: str = "lease_info"\n purpose: str = """\n Collect information about a Commercial Lease.\n """\n terms: Lease\n```\n\nThen define a `LeaseExtractorAgent` with a method `lease_info` that handles this tool,\ninstantiate the agent, and enable it to use and respond to this tool:\n\n```python\nclass LeaseExtractorAgent(ChatAgent):\n def lease_info(self, message: LeaseMessage) -> str:\n print(\n f"""\n DONE! Successfully extracted Lease Info:\n {message.terms}\n """\n )\n return json.dumps(message.terms.dict())\n \nlease_extractor_agent = LeaseExtractorAgent(\n ChatAgentConfig(\n llm=OpenAIGPTConfig(),\n use_functions_api=False,\n use_tools=True,\n )\n)\nlease_extractor_agent.enable_message(LeaseMessage)\n```\n\nSee the [`chat_multi_extract.py`](https://github.com/langroid/langroid-examples/blob/main/examples/docqa/chat_multi_extract.py)\nscript in the `langroid-examples` repo for a full working example.\n\n---\n\n## Chat with documents (file paths, URLs, etc) <a name="agent-docs"></a>\n\nLangroid provides a specialized agent class `DocChatAgent` for this purpose.\nIt incorporates document sharding, embedding, storage in a vector-DB, \nand retrieval-augmented query-answer generation.\nUsing this class to chat with a collection of documents is easy.\nFirst create a `DocChatAgentConfig` instance, with a \n`doc_paths` field that specifies the documents to chat with.\n\n```python\nfrom langroid.agent.doc_chat_agent import DocChatAgentConfig\nconfig = DocChatAgentConfig(\n doc_paths = [\n "https://en.wikipedia.org/wiki/Language_model",\n "https://en.wikipedia.org/wiki/N-gram_language_model",\n "/path/to/my/notes-on-language-models.txt",\n ]\n llm = OpenAIGPTConfig(\n chat_model=OpenAIChatModel.GPT4,\n ),\n vecdb=VectorStoreConfig(\n type="qdrant",\n ),\n)\n```\n\nThen instantiate the `DocChatAgent`, ingest the docs into the vector-store:\n\n```python\nagent = DocChatAgent(config)\nagent.ingest()\n```\nThen we can either ask the agent one-off questions,\n```python\nagent.chat("What is a language model?")\n```\nor wrap it in a `Task` and run an interactive loop with the user:\n```python\nfrom langroid.task import Task\ntask = Task(agent)\ntask.run()\n```\n\nSee full working scripts in the \n[`docqa`](https://github.com/langroid/langroid-examples/tree/main/examples/docqa)\nfolder of the `langroid-examples` repo.\n\n---\n\n# Contributors\n\n- Prasad Chalasani (IIT BTech/CS, CMU PhD/ML; Independent ML Consultant)\n- Somesh Jha (IIT BTech/CS, CMU PhD/CS; Professor of CS, U Wisc at Madison)\n- Mohannad Alhanahnah (Research Associate, U Wisc at Madison)\n- Ashish Hooda (IIT BTech/CS; PhD Candidate, U Wisc at Madison)\n\n',
73
- 'author': 'Prasad Chalasani',
74
- 'author_email': 'pchalasani@gmail.com',
75
- 'maintainer': 'None',
76
- 'maintainer_email': 'None',
77
- 'url': 'None',
78
- 'packages': packages,
79
- 'package_data': package_data,
80
- 'install_requires': install_requires,
81
- 'extras_require': extras_require,
82
- 'python_requires': '>=3.8.1,<3.12',
83
- }
84
-
85
-
86
- setup(**setup_kwargs)
File without changes
File without changes
File without changes