├── .env_example ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── 1_bug_report.yaml │ ├── 2_suggest_improvement.yaml │ ├── 3_feature_request.yaml │ ├── 4_documenting.yaml │ ├── 5_suggest_integration.yaml │ ├── 6_suggest_usecases_benchmarks.yaml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── documentation.yml │ └── python-test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CNAME ├── LICENSE.md ├── Makefile ├── README.md ├── adalflow ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── PACKAGING.md ├── README.md ├── adalflow │ ├── __init__.py │ ├── components │ │ ├── __init__.py │ │ ├── agent │ │ │ ├── README.md │ │ │ ├── __init__.py │ │ │ └── react.py │ │ ├── data_process │ │ │ ├── __init__.py │ │ │ ├── data_components.py │ │ │ └── text_splitter.py │ │ ├── memory │ │ │ ├── __init__.py │ │ │ └── memory.py │ │ ├── model_client │ │ │ ├── __init__.py │ │ │ ├── anthropic_client.py │ │ │ ├── azureai_client.py │ │ │ ├── bedrock_client.py │ │ │ ├── cohere_client.py │ │ │ ├── deepseek_client.py │ │ │ ├── fireworks_client.py │ │ │ ├── google_client.py │ │ │ ├── groq_client.py │ │ │ ├── mistral_client.py │ │ │ ├── ollama_client.py │ │ │ ├── openai_client.py │ │ │ ├── sambanova_client.py │ │ │ ├── together_client.py │ │ │ ├── transformers_client.py │ │ │ ├── utils.py │ │ │ └── xai_client.py │ │ ├── output_parsers │ │ │ ├── __init__.py │ │ │ ├── dataclass_parser.py │ │ │ └── outputs.py │ │ └── retriever │ │ │ ├── __init__.py │ │ │ ├── bm25_retriever.py │ │ │ ├── faiss_retriever.py │ │ │ ├── lancedb_retriver.py │ │ │ ├── llm_retriever.py │ │ │ ├── postgres_retriever.py │ │ │ ├── qdrant_retriever.py │ │ │ └── reranker_retriever.py │ ├── core │ │ ├── __init__.py │ │ ├── base_data_class.py │ │ ├── component.py │ │ ├── container.py │ │ ├── db.py │ │ ├── default_prompt_template.py │ │ ├── embedder.py │ │ ├── func_tool.py │ │ ├── functional.py │ │ ├── generator.py │ │ ├── model_client.py │ │ ├── prompt_builder.py │ │ ├── retriever.py │ │ ├── string_parser.py │ │ ├── tokenizer.py │ │ ├── tool_manager.py │ │ └── types.py │ ├── database │ │ ├── README.md │ │ ├── __init__.py │ │ └── sqlalchemy │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── model.py │ │ │ ├── pipeline │ │ │ ├── __init__.py │ │ │ ├── create_tables.py │ │ │ ├── default_config.py │ │ │ └── inject_data.py │ │ │ └── sqlachemy_manager.py │ ├── datasets │ │ ├── __init__.py │ │ ├── big_bench_hard.py │ │ ├── gsm8k.py │ │ ├── hotpot_qa.py │ │ ├── trec.py │ │ ├── types.py │ │ └── utils.py │ ├── eval │ │ ├── __init__.py │ │ ├── answer_match_acc.py │ │ ├── base.py │ │ ├── functional.py │ │ ├── g_eval.py │ │ ├── llm_as_judge.py │ │ ├── retriever_recall.py │ │ └── utils.py │ ├── optim │ │ ├── README.md │ │ ├── __init__.py │ │ ├── _llm_optimizer.py │ │ ├── few_shot │ │ │ ├── __init__.py │ │ │ └── bootstrap_optimizer.py │ │ ├── function.py │ │ ├── grad_component.py │ │ ├── gradient.py │ │ ├── loss_component.py │ │ ├── optimizer.py │ │ ├── parameter.py │ │ ├── sampler.py │ │ ├── text_grad │ │ │ ├── __init__.py │ │ │ ├── backend_engine_prompt.py │ │ │ ├── llm_text_loss.py │ │ │ ├── ops.py │ │ │ ├── text_loss_with_eval_fn.py │ │ │ └── tgd_optimizer.py │ │ ├── trainer │ │ │ ├── __init__.py │ │ │ ├── adal.py │ │ │ └── trainer.py │ │ └── types.py │ ├── tracing │ │ ├── __init__.py │ │ ├── callback_manager.py │ │ ├── decorators.py │ │ ├── generator_call_logger.py │ │ └── generator_state_logger.py │ └── utils │ │ ├── __init__.py │ │ ├── cache.py │ │ ├── config.py │ │ ├── data.py │ │ ├── file_io.py │ │ ├── global_config.py │ │ ├── lazy_import.py │ │ ├── logger.py │ │ ├── registry.py │ │ ├── serialization.py │ │ └── setup_env.py ├── poetry.lock ├── pyproject.toml ├── pytest.ini └── tests │ ├── README.md │ ├── __init__.py │ ├── _test_optimizer.py │ ├── _test_sampler.py │ ├── test_AzureClient.py │ ├── test_aws_bedrock_client.py │ ├── test_base_data_class.py │ ├── test_component.py │ ├── test_componentlist.py │ ├── test_data.py │ ├── test_data_class_parser.py │ ├── test_data_classes.py │ ├── test_data_loader.py │ ├── test_dataclass_object_functions.py │ ├── test_deepseek_client.py │ ├── test_evaluators.py │ ├── test_faiss_retriever.py │ ├── test_function_expression_parse.py │ ├── test_generator.py │ ├── test_generator_call_logger.py │ ├── test_google_ai_client.py │ ├── test_grad_component.py │ ├── test_groq_client.py │ ├── test_lancedb_retriver.py │ ├── test_lazy_import.py │ ├── test_llm_retriever.py │ ├── test_local_db.py │ ├── test_logger.py │ ├── test_memory.py │ ├── test_model_client.py │ ├── test_ollama_client.py │ ├── test_openai_client.py │ ├── test_output_parser.py │ ├── test_parameter.py │ ├── test_parameter_text_grad.py │ ├── test_qdrant_retriever.py │ ├── test_random_sample.py │ ├── test_react_agent.py │ ├── test_sequential.py │ ├── test_string_parser.py │ ├── test_text_splitter.py │ ├── test_tool.py │ ├── test_trainer.py │ └── test_transformer_client.py ├── benchmarks ├── BHH_object_count │ ├── __init__.py │ ├── dspy_count.py │ ├── models │ │ └── text_grad │ │ │ └── sta.py │ ├── text_grad │ │ ├── __init__.py │ │ ├── config.py │ │ ├── src.py │ │ ├── text_grad_train.py │ │ └── trec_6_train.py │ └── train.py ├── README.md ├── __init__.py ├── config.py ├── hotpot_qa │ ├── __init__.py │ ├── adal_exp │ │ ├── __init__.py │ │ ├── adal_task.py │ │ ├── build_multi_hop_rag.py │ │ ├── build_vanilla_rag.py │ │ ├── train_agent_rag.py │ │ ├── train_multi_hop_rag.py │ │ ├── train_multi_hop_rag_cycle.py │ │ ├── train_multi_hop_retriever.py │ │ ├── train_vanilla.py │ │ └── train_vanilla_rag.py │ ├── config.py │ ├── dspy_multi_hop_rag.py │ ├── dspy_multi_hop_rag_cycle.py │ └── dspy_vanilla_rag.py └── trec_classification │ └── dspy_train_few_shot_boostrap.py ├── docs ├── .gitignore ├── CHANGLOG.md ├── Makefile ├── README.md ├── _dummy │ └── dummy │ │ └── __init__.py ├── make.bat ├── poetry.lock ├── pyproject.toml ├── requirements.txt └── source │ ├── _static │ ├── class_hierarchy.html │ ├── css │ │ └── custom.css │ └── images │ │ ├── AdalFlow.svg │ │ ├── AdalFlow_black_bg.svg │ │ ├── AdalFlow_task_pipeline.png │ │ ├── G_eval_structure.png │ │ ├── LLM_arch.png │ │ ├── LightRAG-logo-circle.png │ │ ├── LightRAG-logo-doc.jpeg │ │ ├── LightRAG-logo.jpg │ │ ├── LightRAG_dataflow.png │ │ ├── RAG_Enhancements.png │ │ ├── RAG_architecture.png │ │ ├── RAG_workflow.png │ │ ├── REALM_train_architecture.png │ │ ├── ReAct.jpg │ │ ├── Trainable_task_pipeline.png │ │ ├── adalflow-logo.png │ │ ├── adalflow_code_samples.png │ │ ├── adalflow_debug_report.png │ │ ├── adalflow_files.png │ │ ├── adalflow_issue_template.png │ │ ├── adalflow_issues.png │ │ ├── adalflow_rag_benchmarks.png │ │ ├── anthropic.png │ │ ├── azure.png │ │ ├── bedrock.png │ │ ├── classification_opt_prompt.png │ │ ├── classification_training_map.png │ │ ├── cohere.png │ │ ├── database.png │ │ ├── dataclass.png │ │ ├── deepseek.png │ │ ├── embedder.png │ │ ├── example_auto_grad_graph.png │ │ ├── fireworks.png │ │ ├── generator.png │ │ ├── grok.png │ │ ├── groq.png │ │ ├── huggingface.png │ │ ├── lance.png │ │ ├── lancedb.png │ │ ├── lightrag_structure.png │ │ ├── mistral.png │ │ ├── model_client.png │ │ ├── multi-providers.png │ │ ├── ollama.png │ │ ├── openai.png │ │ ├── pr_draft.png │ │ ├── qdrant.png │ │ ├── query_1.png │ │ ├── query_2.png │ │ ├── replug.png │ │ ├── retriever.png │ │ ├── sambanova.png │ │ ├── self_rag.png │ │ ├── tensor_parameter.png │ │ ├── together.png │ │ ├── trace_graph_EvalFnToTextLoss_output_id_6ea5da3c-d414-4aae-8462-75dd1e09abab.png │ │ ├── trace_graph_Generator_output_id_689cc5a1-6737-40a8-8faa-8bbf7bddfed8.png │ │ ├── trace_graph_sum.png │ │ ├── trace_graph_sum_id_e53cb8f9-235d-480b-b630-f480a9dfb5d0.png │ │ ├── trainer.png │ │ └── xai.png │ ├── _templates │ ├── github-link.html │ ├── package.rst_t │ └── pydata_sphinx_theme │ │ └── layout.html │ ├── apis │ ├── components │ │ └── index.rst │ ├── core │ │ └── index.rst │ ├── datasets │ │ └── index.rst │ ├── eval │ │ └── index.rst │ ├── index.rst │ ├── optim │ │ └── index.rst │ ├── tracing │ │ └── index.rst │ └── utils │ │ └── index.rst │ ├── change_api_file_name.py │ ├── conf.py │ ├── contributor │ ├── contribute_to_code.rst │ ├── contribution.rst │ └── index.rst │ ├── get_started │ ├── adalflow_in_15mins.rst │ ├── community.rst │ ├── index.rst │ ├── installation.rst │ └── openai.jpg │ ├── index.rst │ ├── insert_autosummary.py │ ├── insert_labels.py │ ├── integrations │ ├── index.rst │ └── integrations.rst │ ├── new_tutorials │ ├── embedder.rst │ ├── generator.rst │ ├── index.rst │ ├── introduction.rst │ ├── parser.rst │ └── prompt.rst │ ├── remove_files.py │ ├── remove_string.py │ ├── tutorials │ ├── adalcomponent.rst │ ├── agent.rst │ ├── auto_text_grad.rst │ ├── base_data_class.rst │ ├── ckpt_file.rst │ ├── class_hierarchy.rst │ ├── component.rst │ ├── configs.rst │ ├── data_class.py │ ├── data_pipeline.rst │ ├── datasets.rst │ ├── db.rst │ ├── embedder.rst │ ├── evaluation.rst │ ├── few_shot_optimizer.rst │ ├── generator.rst │ ├── index.rst │ ├── lightrag_design_philosophy.rst │ ├── logging.rst │ ├── logging_tracing.rst │ ├── model_client.rst │ ├── optimizer.rst │ ├── output_parsers.rst │ ├── parameter.rst │ ├── prompt.rst │ ├── rag_playbook.rst │ ├── rag_with_memory.rst │ ├── retriever.rst │ ├── text_splitter.rst │ ├── tool_helper.rst │ ├── trace_graph.rst │ └── trainer.rst │ └── use_cases │ ├── build_a_rag.rst │ ├── classification.rst │ ├── eval_a_rag.rst │ ├── index.rst │ ├── introduction_to_basedataclass.rst │ ├── logging.rst │ ├── multi_hop_rag_opt.rst │ ├── qa_computation_graph.rst │ ├── qa_demo_trace_graph.rst │ ├── qa_text_grad_trace_graph.rst │ ├── question_answering.rst │ ├── question_answering_word_sort.rst │ ├── rag_end_to_end.rst │ └── rag_opt.rst ├── notebooks ├── README.md ├── adalflow_colab_template.ipynb ├── evaluation │ └── adalflow_llm_eval.ipynb ├── integration │ ├── __init__.py │ ├── adalflow_together_deepseek_r1.ipynb │ ├── fireworks_integration.ipynb │ ├── mistral_integration.ipynb │ ├── sambanova_integration.ipynb │ └── xai_integration.ipynb ├── qas │ └── adalflow_object_count_auto_optimization.ipynb ├── tutorials │ ├── adalflow_classification_optimization.ipynb │ ├── adalflow_component.ipynb │ ├── adalflow_dataclasses.ipynb │ ├── adalflow_embedder.ipynb │ ├── adalflow_function_calls.ipynb │ ├── adalflow_logger.ipynb │ ├── adalflow_modelclient.ipynb │ ├── adalflow_rag_optimization.ipynb │ ├── adalflow_rag_playbook.ipynb │ ├── adalflow_text_splitter.ipynb │ └── adalflow_tracing.ipynb └── use_cases │ └── adalflow_rag_optimization.ipynb ├── poetry.lock ├── pyproject.toml ├── tutorials ├── .gitignore ├── __init__.py ├── adalflow_dataclasses.py ├── adalflow_embedder.py ├── adalflow_function_calls.py ├── adalflow_logger.py ├── adalflow_modelclient_sync_and_async.py ├── adalflow_text_splitter.py ├── adalflow_tracing.py ├── component.py ├── database.ipynb ├── dataclass.ipynb ├── deepseek_note.py ├── default_config.json ├── embedder.ipynb ├── evaluation │ ├── eval_nlg.py │ └── eval_retriever.py ├── generator.ipynb ├── generator_all_providers.py ├── generator_note.py ├── logging_config.py ├── model_client.ipynb ├── multimodal_client_testing_examples.py ├── ollama_client_note.py ├── ollama_client_simple_qa.py ├── parser_note.py ├── paul_graham │ └── paul_graham_essay.txt ├── postgres.sql ├── prompt_note.py ├── rag.ipynb ├── rag │ ├── config.py │ └── rag.py ├── react_note.ipynb ├── react_note.py ├── retriever.ipynb ├── retriever │ ├── __init__.py │ ├── adalflow_lancedb.py │ ├── data.py │ └── local_db.py ├── task_pipeline.py ├── tools.ipynb └── tools.py └── use_cases ├── .gitignore ├── README.md ├── __init__.py ├── agent └── react_agent_hotpot_qa.ipynb ├── bmp_train.py ├── classification ├── __init__.py ├── data.py ├── eval.py ├── prepare_for_train.py ├── train.py ├── train_string_output.py ├── trec_task_string_output.py ├── trec_task_structured_output.py └── visualize.py ├── config.py ├── configs ├── rag.yaml └── rag_hotpotqa.yaml ├── generator ├── basic.ipynb └── intermediate.ipynb ├── question_answering ├── __init__.py ├── bbh │ ├── __init__.py │ ├── data.py │ ├── object_count │ │ ├── __init__.py │ │ ├── diagnose.py │ │ ├── task.py │ │ └── train_new.py │ └── word_sorting │ │ ├── diagnose.py │ │ ├── task.py │ │ ├── train.py │ │ └── train_paper.py ├── chatbot.ipynb ├── gsm8k │ ├── task.py │ └── train.py └── simple_qa.ipynb ├── rag ├── __init__.py ├── bootstrap_weak_model.py ├── build │ ├── README.md │ └── rag.py ├── rag_with_eval.py └── simple_rag.yaml ├── tracing └── trace_generator.py └── unsorted ├── fewshot_qa.py ├── llm_as_retriever.py ├── rag_hotpotqa.py ├── rag_optimized.py ├── rag_yaml_config.py ├── retriever_llm.py ├── simple_qa.py ├── simple_qa_anthropic.py ├── simple_qa_google.py ├── simple_qa_groq.py ├── simple_qa_memory.py ├── simple_qa_stream.py ├── simple_qa_trainable.py ├── simple_rag_bm_25.py ├── use_embedder.py └── yaml_output.py /.env_example: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY=YOUR_API_KEY_IF_YOU_USE_OPENAI 2 | GROQ_API_KEY=YOUR_API_KEY_IF_YOU_USE_GROQ 3 | ANTHROPIC_API_KEY=YOUR_API_KEY_IF_YOU_USE_ANTHROPIC 4 | GOOGLE_API_KEY=YOUR_API_KEY_IF_YOU_USE_GOOGLE 5 | COHERE_API_KEY=YOUR_API_KEY_IF_YOU_USE_COHERE 6 | HF_TOKEN=YOUR_API_KEY_IF_YOU_USE_HF 7 | OLLAMA_HOST=http://localhost:11434 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ipynb linguist-language=Jupyter Notebook 2 | *.ipynb linguist-vendored 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Report a bug 2 | description: Any errors that you encounter. 3 | labels: ['bug'] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: > 8 | Before you go any further. Is this really a **🐛 bug**? 9 | 10 | If it's a question about how AdalFlow works, have a look at our [AdalFlow documentation](https://adalflow.sylph.ai/) 11 | or ask a question on our [Community Discord](https://discord.gg/ezzszrRZvT). 12 | 13 | - type: textarea 14 | attributes: 15 | label: Bug description 16 | description: A description of the 🐛bug🐛. 17 | placeholder: | 18 | A clear and concise description of what the bug is. 19 | 20 | Include steps to reproduce, the expected behaviour, and the actual behaviour. 21 | 22 | ``` 23 | The error message you got, with the full traceback if available. 24 | ``` 25 | validations: 26 | required: true 27 | 28 | - type: textarea 29 | id: versions 30 | attributes: 31 | label: What version are you seeing the problem on? 32 | description: Use `adalflow.__version__` to get the version if it's via pip or "main branch" if you're using the latest code. 33 | render: python 34 | validations: 35 | required: false 36 | 37 | - type: markdown 38 | attributes: 39 | value: '**Note: The rest of this form is optional, but filling it out may help us to provide better support.**' 40 | 41 | - type: textarea 42 | attributes: 43 | label: How to reproduce the bug 44 | description: > 45 | Provide steps and example code here. 46 | You can also paste a link to Google Colab. 47 | ```python 48 | # Sample code to reproduce the problem 49 | ``` 50 | render: python 51 | validations: 52 | required: false 53 | 54 | - type: textarea 55 | attributes: 56 | label: Error messages and logs 57 | description: > 58 | Provide any error messages and/or logs 59 | placeholder: '# Copy the complete error messages and logs' 60 | value: | 61 | ``` 62 | # Error messages and logs here please 63 | ``` 64 | validations: 65 | required: false 66 | 67 | - type: textarea 68 | attributes: 69 | label: Environment 70 | description: | 71 | Please provide details about your environment, including the following: 72 | - OS (e.g., Linux, Windows, macOS) 73 | value: | 74 | - OS: [e.g., Linux, Windows, macOS] 75 | validations: 76 | required: false 77 | 78 | - type: textarea 79 | attributes: 80 | label: More info 81 | description: Add any other info about the issue here. 82 | validations: 83 | required: false 84 | 85 | - type: markdown 86 | attributes: 87 | value: '**Happy engineering!**' 88 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_suggest_improvement.yaml: -------------------------------------------------------------------------------- 1 | name: Improvement suggestion 2 | description: Suggest an improvement, a code refactor, or deprecation 3 | labels: ['[adalflow] improvement'] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Outline & Motivation 8 | description: A clear and concise description of the improvement suggestion 9 | placeholder: | 10 | Please outline the motivation for the proposal. 11 | If this is related to another GitHub issue, please link it here 12 | validations: 13 | required: true 14 | 15 | - type: textarea 16 | attributes: 17 | label: Pitch 18 | description: A clear and concise description of what you want to happen. 19 | validations: 20 | required: false 21 | 22 | - type: textarea 23 | attributes: 24 | label: Additional context 25 | description: Add any other context or screenshots here. 26 | validations: 27 | required: false 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Propose a feature for this project 3 | labels: ["[adalflow] new feature request"] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Description & Motivation 8 | description: A clear and concise description of the feature proposal 9 | placeholder: | 10 | Please outline the motivation for the proposal. 11 | Is your feature request related to a problem? e.g., I'm always frustrated when [...]. 12 | If this is related to another GitHub issue, please link it here 13 | 14 | - type: textarea 15 | attributes: 16 | label: Pitch 17 | description: A clear and concise description of what you want to happen. 18 | validations: 19 | required: false 20 | 21 | - type: textarea 22 | attributes: 23 | label: Alternatives 24 | description: A clear and concise description of any alternative solutions or features you've considered, if any. 25 | validations: 26 | required: false 27 | 28 | - type: textarea 29 | attributes: 30 | label: Additional context 31 | description: Add any other context or screenshots about the feature request here. 32 | validations: 33 | required: false 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4_documenting.yaml: -------------------------------------------------------------------------------- 1 | name: Typos and doc fixes 2 | description: Tell us about how we can improve our documentation and Google colab/ipynb notebooks. 3 | labels: ["documentation"] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: 📚 Documentation 8 | description: A description of the 🐛bug🐛. 9 | placeholder: | 10 | For typos and doc fixes, please go ahead and: 11 | 12 | - For a simlpe typo or fix, please send directly a PR (no need to create an issue) 13 | - If you are not sure about the proper solution, please describe here your finding... 14 | 15 | validations: 16 | required: true 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/5_suggest_integration.yaml: -------------------------------------------------------------------------------- 1 | name: New integration proposal 2 | description: Propose a new integration for this project, either db, retriever, model_client. We highly recommend you to find a POC from the provider team to work together on this. 3 | labels: ['[adalflow] integration'] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Description & Motivation 8 | description: A clear and concise description of the integration proposal 9 | placeholder: | 10 | Please outline the motivation for the proposal. 11 | 12 | 13 | - type: textarea 14 | attributes: 15 | label: Pitch 16 | description: A clear and concise description of what you want to happen. 17 | validations: 18 | required: false 19 | 20 | - type: textarea 21 | attributes: 22 | label: Provider POC 23 | description: If you have a POC from the provider team, please provide it here. 24 | validations: 25 | required: false 26 | 27 | - type: textarea 28 | attributes: 29 | label: Additional context 30 | description: Add any other context or screenshots about the integration request here. 31 | validations: 32 | required: false 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/6_suggest_usecases_benchmarks.yaml: -------------------------------------------------------------------------------- 1 | name: Suggest use cases and benchmarks 2 | description: Propose new use cases that AdalFlow should support or benchmarks that we should compare against 3 | labels: ["new use cases/benchmarks"] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Description & Motivation 8 | description: A clear and concise description of the new use case or benchmark proposal 9 | placeholder: | 10 | Please outline the motivation for the proposal. 11 | 12 | 13 | - type: textarea 14 | attributes: 15 | label: Pitch 16 | description: A clear and concise description of what you want to happen. 17 | validations: 18 | required: false 19 | 20 | - type: textarea 21 | attributes: 22 | label: Alternatives 23 | description: A clear and concise description of any alternative solutions or features you've considered, if any. 24 | validations: 25 | required: false 26 | 27 | - type: textarea 28 | attributes: 29 | label: Additional context 30 | description: Add any other context or screenshots about the feature request here. 31 | validations: 32 | required: false 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 👍 Upvote an issue 4 | url: https://github.com/SylphAI-Inc/AdalFlow/issues 5 | about: You should upvote an issue if it is important to you. 6 | - name: 💬 Chat with us 7 | url: https://discord.gg/ezzszrRZvT 8 | about: Live chat with experts, engineers, and users in our Discord community. 9 | - name: 📖 Read the documentation 10 | url: http://adalflow.sylph.ai/ 11 | about: Please consult the documentation before opening any issues! 12 | # - name: 🙋 Contact us about professional services 13 | # url: https://lightning.ai 14 | # about: Contact the Lightning.ai sales team for paid support. 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What does this PR do? 2 | 3 | 12 | 13 | Fixes #\ 14 | 15 | 16 | 17 |
18 | Before submitting 19 | 20 | - Was this **discussed/agreed** via a GitHub issue? (not for typos and docs) 21 | - [ ] Did you read the [contributor guideline](https://adalflow.sylph.ai/contributor/index.html)? 22 | - [ ] Did you make sure your **PR does only one thing**, instead of bundling different changes together? 23 | - Did you make sure to **update the documentation** with your changes? (if necessary) 24 | - Did you write any **new necessary tests**? (not for typos and docs) 25 | - [ ] Did you verify new and **existing tests pass** locally with your changes? 26 | - Did you list all the **breaking changes** introduced by this pull request? 27 | 28 | 29 |
30 | 31 | 32 | 39 | -------------------------------------------------------------------------------- /.github/workflows/python-test.yml: -------------------------------------------------------------------------------- 1 | name: Python Tests 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | python-version: ['3.9', '3.10', '3.11', '3.12'] 15 | 16 | steps: 17 | - uses: actions/checkout@v4 # Updated to the latest version 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v4 # Updated to the latest version 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | 23 | - name: Install Poetry 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install poetry 27 | 28 | - name: Install dependencies 29 | run: | 30 | cd adalflow 31 | poetry config virtualenvs.create false 32 | poetry install 33 | 34 | - name: Run tests with pytest 35 | run: | 36 | cd adalflow 37 | poetry run pytest 38 | 39 | - name: Upload pytest results as an artifact (optional) 40 | uses: actions/upload-artifact@v4 # Updated to the latest version 41 | if: always() # Always run this step to ensure test results are saved even if previous steps fail 42 | with: 43 | name: pytest-results 44 | path: adalflow/.pytest_cache 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | .vscode 3 | .DS_Store 4 | .env 5 | test_llamaindex.py 6 | outputs.txt 7 | core/__pycache__ 8 | adalflow/__pycache__ 9 | components/*/__pycache__ 10 | components/__pycache__ 11 | use_cases/__pycache__ 12 | */__pycache__ 13 | dist/ 14 | lib/ 15 | __pycache__/ 16 | # docs/source/ 17 | docs/build/ 18 | docs/_build/ 19 | # docs/source/_templates 20 | docs/source/documents/ 21 | # docs/source/apis/* 22 | .mypy_cache/ 23 | .pytest_cache/ 24 | local_cache/ 25 | /*.txt 26 | *.pth 27 | *.log 28 | storage/ 29 | *.pkl 30 | # /*.png 31 | /*.dot 32 | /*.csv 33 | index.faiss 34 | *.json 35 | # ignore the softlink to adalflow cache 36 | *.adalflow 37 | .idea 38 | extend/ 39 | logs/ 40 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.0.1 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - id: check-added-large-files 8 | args: ['--maxkb=4000'] 9 | - id: debug-statements 10 | - id: detect-private-key 11 | 12 | - repo: https://github.com/psf/black 13 | rev: 24.4.2 14 | hooks: 15 | - id: black 16 | args: ['--line-length=88'] 17 | exclude: ^docs/|.*\.(json|yaml|md|txt)$ 18 | 19 | - repo: https://github.com/astral-sh/ruff-pre-commit 20 | rev: v0.4.2 21 | hooks: 22 | # Run the linter. 23 | - id: ruff 24 | args: ['--fix'] 25 | exclude: ^docs/|.*\.(json|yaml|md|txt)$ 26 | 27 | # Add local hooks to run custom commands 28 | - repo: local 29 | hooks: 30 | - id: run-make-format 31 | name: Run Make Format 32 | entry: make format 33 | language: system 34 | pass_filenames: false 35 | # - repo: https://github.com/pycqa/flake8 36 | # rev: 4.0.1 37 | # hooks: 38 | # - id: flake8 39 | # args: ['--max-line-length=88'] 40 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | adalflow.sylph.ai 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) SylphAI, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Define variables for common directories and commands 2 | PYTHON = poetry run 3 | SRC_DIR = . 4 | 5 | # Default target: Show help 6 | .PHONY: help 7 | help: 8 | @echo "Available targets:" 9 | @echo " setup Install dependencies and set up pre-commit hooks" 10 | @echo " format Run Black and Ruff to format the code" 11 | @echo " lint Run Ruff to check code quality" 12 | @echo " test Run tests with pytest" 13 | @echo " precommit Run pre-commit hooks on all files" 14 | @echo " clean Clean up temporary files and build artifacts" 15 | 16 | # Install dependencies and set up pre-commit hooks 17 | .PHONY: setup 18 | setup: 19 | poetry install 20 | poetry run pre-commit install 21 | 22 | # Format code using Black and Ruff 23 | .PHONY: format 24 | format: 25 | $(PYTHON) black $(SRC_DIR) 26 | git ls-files | xargs pre-commit run black --files 27 | 28 | # Run lint checks using Ruff 29 | .PHONY: lint 30 | lint: 31 | $(PYTHON) ruff check $(SRC_DIR) 32 | 33 | # Run all pre-commit hooks on all files 34 | .PHONY: precommit 35 | precommit: 36 | $(PYTHON) pre-commit run --all-files 37 | 38 | # Run tests 39 | .PHONY: test 40 | test: 41 | $(PYTHON) pytest 42 | 43 | # Clean up temporary files and build artifacts 44 | .PHONY: clean 45 | clean: 46 | rm -rf .pytest_cache 47 | rm -rf .mypy_cache 48 | rm -rf __pycache__ 49 | rm -rf build dist *.egg-info 50 | find . -type d -name "__pycache__" -exec rm -r {} + 51 | find . -type f -name "*.pyc" -delete 52 | -------------------------------------------------------------------------------- /adalflow/.gitignore: -------------------------------------------------------------------------------- 1 | tests/log 2 | *.png 3 | *.svg 4 | CONTRIBUTING.md 5 | -------------------------------------------------------------------------------- /adalflow/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) SylphAI, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /adalflow/PACKAGING.md: -------------------------------------------------------------------------------- 1 | # Poetry Packaging Guide 2 | ## Development 3 | 4 | To install optional dependencies, use the following command: 5 | 6 | ```bash 7 | poetry install --extras "openai groq faiss" 8 | ``` 9 | Install more extra after the first installation, you will use the same command: 10 | 11 | ```bash 12 | poetry install --extras "anthropic cohere google-generativeai pgvector" 13 | ``` 14 | 15 | ## Extra Dependencies 16 | Add the optional package in dependencides. 17 | 18 | Build it locally: 19 | ```bash 20 | poetry build 21 | ``` 22 | 23 | Test the package locally: 24 | 25 | Better to use a colab to update the whl file and test the installation. 26 | 27 | ```bash 28 | pip install "dist/adalflow-0.1.0b1-py3-none-any.whl[openai,groq,faiss]" 29 | ``` 30 | 31 | 32 | ## Update the version 33 | 34 | 1. Update the version in `pyproject.toml` 35 | 2. Add the version number in `adalflow/__init__.py` 36 | 3. Build the package 37 | 4. Test the package locally 38 | 5. Push the changes to the repository 39 | 6. Ensure to run `poetry lock --no-update` in the root directory (project-level) to update the lock file for other directories such as `tutorials`, `use_cases`, `benchmarks`, etc. 40 | 7. Update the `CHANGELOG.md` file with the new version number and the changes made in the new version. 41 | 42 | ## TODO: we need to automate the version update process. Help is appreciated. 43 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/adalflow/components/__init__.py -------------------------------------------------------------------------------- /adalflow/adalflow/components/agent/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Agent is not a model or LLM model. 3 | # Agent is better defined as a system that uses LLM models to plan and replan steps that each involves the usage of various tools, 4 | # such as function calls, another LLM model based on the context and history (memory) to complete a task autonomously. 5 | 6 | 7 | # REact agent can be useful for 8 | # - Multi-hop reasoning [Q&A], including dividing the query into subqueries and answering them one by one. 9 | # - Plan the usage of the given tools: highly flexible. Retriever, Generator modules or any other functions can all be wrapped as tools. 10 | 11 | # The initial ReAct paper does not support different types of tools. We have greatly extended the flexibility of tool adaption, even including an llm tool 12 | # to answer questions that cant be answered or better be answered by llm using its world knowledge. 13 | # - Every react agent can be given a different tasks, different tools, and different LLM models to complete the task. 14 | # - 'finish' tool is defined to finish the task by joining all subqueries answers. 15 | 16 | # Reference: 17 | # [1] LLM Agent survey: https://github.com/Paitesanshi/LLM-Agent-Survey 18 | Agent is not a model or LLM model. 19 | 20 | Agent is better defined as a system that uses LLM models to plan and replan steps that each involves the usage of various tools, 21 | such as function calls, another LLM model based on the context and history (memory) to complete a task autonomously. 22 | 23 | The future: the agent can write your prompts too. Check out dspy: https://github.com/stanfordnlp/dspy 24 | 25 | In this directory, we add the general design patterns of agent, here are four (Thanks to Andrew Ng): 26 | 27 | 1️⃣ Reflection 28 | 29 | - Self-Refine: Iterative Refinement with Self-Feedback 30 | - Reflexion: Language Agents with Verbal Reinforcement Learning 31 | 32 | 2️⃣ Tool use 33 | 34 | - Gorilla: Large Language Model Connected with Massive APIs 35 | - MM-REACT: Prompting ChatGPT for Multimodal Reasoning and Action 36 | 37 | 3️⃣ Planning 38 | 39 | - Chain-of-Thought Prompting Elicits Reasoning in Large Language Models 40 | - HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face 41 | - React 42 | 43 | 4️⃣ Multi-agent collaboration 44 | 45 | - Communicative Agents for Software Development 46 | - AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation 47 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/agent/__init__.py: -------------------------------------------------------------------------------- 1 | from .react import DEFAULT_REACT_AGENT_SYSTEM_PROMPT, ReActAgent 2 | from adalflow.utils.registry import EntityMapping 3 | 4 | __all__ = [ 5 | "ReActAgent", 6 | "DEFAULT_REACT_AGENT_SYSTEM_PROMPT", 7 | ] 8 | 9 | for name in __all__: 10 | EntityMapping.register(name, globals()[name]) 11 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/data_process/__init__.py: -------------------------------------------------------------------------------- 1 | """Components here are used for data processing/transformation.""" 2 | 3 | from .text_splitter import TextSplitter 4 | from .data_components import RetrieverOutputToContextStr, ToEmbeddings 5 | from adalflow.utils.registry import EntityMapping 6 | 7 | 8 | __all__ = ["TextSplitter", "RetrieverOutputToContextStr", "ToEmbeddings"] 9 | 10 | for name in __all__: 11 | EntityMapping.register(name, globals()[name]) 12 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/memory/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/adalflow/components/memory/__init__.py -------------------------------------------------------------------------------- /adalflow/adalflow/components/model_client/deepseek_client.py: -------------------------------------------------------------------------------- 1 | from typing import ( 2 | Optional, 3 | Any, 4 | Callable, 5 | Literal, 6 | ) 7 | 8 | from adalflow.utils.lazy_import import safe_import, OptionalPackages 9 | from adalflow.components.model_client.openai_client import OpenAIClient 10 | from openai.types import Completion 11 | 12 | openai = safe_import(OptionalPackages.OPENAI.value[0], OptionalPackages.OPENAI.value[1]) 13 | 14 | 15 | class DeepSeekClient(OpenAIClient): 16 | """ 17 | A component wrapper for the DeepSeek API client. 18 | 19 | DeepSeek's API is compatible with OpenAI's API, making it possible to use OpenAI SDKs 20 | or OpenAI-compatible software with DeepSeek by adjusting the API base URL. 21 | 22 | This client extends `OpenAIClient` but modifies the default `base_url` to use DeepSeek's API. 23 | 24 | Documentation: https://api-docs.deepseek.com/guides/reasoning_model 25 | 26 | Args: 27 | api_key (Optional[str], optional): DeepSeek API key. Defaults to `None`. 28 | chat_completion_parser (Callable[[Completion], Any], optional): A function to parse API responses. 29 | input_type (Literal["text", "messages"], optional): Defines how input is handled. Defaults to `"text"`. 30 | base_url (str, optional): API base URL, defaults to `"https://api.deepseek.com/v1/"`. 31 | """ 32 | 33 | def __init__( 34 | self, 35 | api_key: Optional[str] = None, 36 | chat_completion_parser: Callable[[Completion], Any] = None, 37 | input_type: Literal["text", "messages"] = "messages", 38 | base_url: str = "https://api.deepseek.com/v1/", 39 | env_api_key_name: str = "DEEPSEEK_API_KEY", 40 | ): 41 | """Initializes DeepSeek API client with the correct base URL. The input_type is set to "messages" by default to be compatible with DeepSeek reasoner.""" 42 | super().__init__( 43 | api_key=api_key, 44 | chat_completion_parser=chat_completion_parser, 45 | input_type=input_type, 46 | base_url=base_url, 47 | env_api_key_name=env_api_key_name, 48 | ) 49 | 50 | 51 | # Example usage: 52 | if __name__ == "__main__": 53 | from adalflow.core import Generator 54 | from adalflow.utils import setup_env, get_logger 55 | 56 | log = get_logger(level="DEBUG") 57 | 58 | prompt_kwargs = {"input_str": "What is the meaning of life?"} 59 | 60 | setup_env() 61 | 62 | gen = Generator( 63 | model_client=DeepSeekClient(), 64 | model_kwargs={"model": "deepseek-reasoner", "stream": True}, 65 | ) 66 | 67 | gen_response = gen(prompt_kwargs) 68 | print(f"gen_response: {gen_response}") 69 | 70 | for genout in gen_response.data: 71 | print(f"genout: {genout}") 72 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/model_client/fireworks_client.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Callable, Any, Literal 2 | from openai.types import Completion 3 | from adalflow.components.model_client.openai_client import OpenAIClient 4 | 5 | BASE_URL = "https://api.fireworks.ai/inference/v1/" 6 | 7 | 8 | class FireworksClient(OpenAIClient): 9 | __doc__ = r"""A component wrapper for Fireworks AI's OpenAI-compatible API. 10 | 11 | This class extends :class:`OpenAIClient` by customizing several key parameters: 12 | - Sets the API base URL to ``"https://api.fireworks.ai/inference/v1/"``. 13 | - Uses the environment variable ``"FIREWORKS_API_KEY"`` to obtain the API key. 14 | - Defaults the input type to ``"messages"``, which is suitable for multi-turn chat interactions. 15 | 16 | **Example usage with AdalFlow Generator:** 17 | 18 | .. code-block:: python 19 | 20 | from adalflow.core import Generator 21 | from adalflow.components.model_client.fireworks_client import FireworksClient 22 | 23 | 24 | generator = Generator( 25 | model_client=FireworksClient(), 26 | model_kwargs={ 27 | "model": "accounts/fireworks/models/llama-v3p1-8b-instruct", 28 | "temperature": 0.7, 29 | } 30 | ) 31 | 32 | prompt_kwargs = { 33 | "input_str": "Hello from Fireworks AI! Can you summarize the concept of quantum mechanics?" 34 | } 35 | 36 | response = generator(prompt_kwargs) 37 | """ 38 | 39 | def __init__( 40 | self, 41 | api_key: Optional[str] = None, 42 | chat_completion_parser: Callable[[Completion], Any] = None, 43 | input_type: Literal["text", "messages"] = "text", 44 | base_url: str = BASE_URL, 45 | env_api_key_name: str = "FIREWORKS_API_KEY", 46 | ): 47 | super().__init__( 48 | api_key=api_key, 49 | chat_completion_parser=chat_completion_parser, 50 | input_type=input_type, 51 | base_url=base_url, 52 | env_api_key_name=env_api_key_name, 53 | ) 54 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/model_client/sambanova_client.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Any, Callable, Literal 2 | from openai.types import Completion 3 | from adalflow.components.model_client.openai_client import OpenAIClient 4 | 5 | BASE_URL = "https://api.sambanova.ai/v1/" 6 | __all__ = ["SambaNovaClient"] 7 | 8 | 9 | class SambaNovaClient(OpenAIClient): 10 | __doc__ = r"""A component wrapper for SambaNova's OpenAI-compatible API. 11 | 12 | This client extends :class:`OpenAIClient` and customizes: 13 | - The API key is read from the environment variable ``SAMBANOVA_API_KEY`` if not provided explicitly. 14 | 15 | **Example usage with the AdalFlow Generator:** 16 | 17 | .. code-block:: python 18 | 19 | from adalflow.core import Generator 20 | from adalflow.components.model_client.sambanova_client import SambaNovaClient 21 | 22 | generator = Generator( 23 | model_client=SambaNovaClient(), 24 | model_kwargs={ 25 | "model": "Meta-Llama-3.1-8B-Instruct", 26 | "temperature": 0.7, 27 | "top_p": 0.9, 28 | }, 29 | ) 30 | 31 | prompt_kwargs = { 32 | "input_str": "Hello from SambaNova! Can you summarize the concept of quantum computing in simple terms?" 33 | } 34 | 35 | response = generator(prompt_kwargs) 36 | """ 37 | 38 | def __init__( 39 | self, 40 | api_key: Optional[str] = None, 41 | chat_completion_parser: Callable[[Completion], Any] = None, 42 | input_type: Literal["text", "messages"] = "text", 43 | base_url: str = BASE_URL, 44 | env_api_key_name: str = "SAMBANOVA_API_KEY", 45 | ): 46 | """ 47 | Initialize a SambaNovaClient instance. 48 | 49 | :param api_key: (Optional) SambaNova API key. If not provided, the client attempts to read from the 50 | environment variable ``SAMBANOVA_API_KEY``. 51 | :param chat_completion_parser: (Optional) A custom function to parse SambaNova responses. 52 | :param input_type: Specifies the input format, either ``"text"`` or ``"messages"``. Defaults to ``"messages"``. 53 | :param base_url: SambaNova API endpoint. Defaults to ``"https://api.sambanova.ai/v1/"``. 54 | :param env_api_key_name: The name of the environment variable holding the API key. Defaults to ``SAMBANOVA_API_KEY``. 55 | """ 56 | super().__init__( 57 | api_key=api_key, 58 | chat_completion_parser=chat_completion_parser, 59 | input_type=input_type, 60 | base_url=base_url, 61 | env_api_key_name=env_api_key_name, 62 | ) 63 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/model_client/utils.py: -------------------------------------------------------------------------------- 1 | "Helpers for model client for integrating models and parsing the output." 2 | 3 | from adalflow.core.types import EmbedderOutput, Embedding, Usage 4 | 5 | 6 | def parse_embedding_response( 7 | api_response, 8 | ) -> EmbedderOutput: 9 | r"""Parse embedding model output from the API response to EmbedderOutput. 10 | 11 | Follows the OpenAI API response pattern. 12 | """ 13 | # Assuming `api_response` has `.embeddings` and `.usage` attributes 14 | # and that `embeddings` is a list of objects that can be converted to `Embedding` dataclass 15 | # TODO: check if any embedding is missing 16 | embeddings = [ 17 | Embedding(embedding=e.embedding, index=e.index) for e in api_response.data 18 | ] 19 | usage = Usage( 20 | prompt_tokens=api_response.usage.prompt_tokens, 21 | total_tokens=api_response.usage.total_tokens, 22 | ) # Assuming `usage` is an object with a `count` attribute 23 | 24 | # Assuming the model name is part of the response or set statically here 25 | model = api_response.model 26 | 27 | return EmbedderOutput(data=embeddings, model=model, usage=usage) 28 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/model_client/xai_client.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Any, Callable, Literal 2 | from openai.types import Completion 3 | from adalflow.components.model_client.openai_client import OpenAIClient 4 | 5 | BASE_URL = "https://api.x.ai/v1" 6 | 7 | __all__ = ["XAIClient"] 8 | 9 | 10 | class XAIClient(OpenAIClient): 11 | 12 | __doc__ = r"""xAI's client is built on top of :class:`OpenAIClient` without overriding any methods. 13 | 14 | References: 15 | - To obtain your API key, sign up at: https://x.ai/ 16 | - API documentation: https://docs.x.ai/docs/api-reference#list-models 17 | 18 | **Example usage with the AdalFlow Generator:** 19 | 20 | .. code-block:: python 21 | 22 | from adalflow.core import Generator 23 | from adalflow.components.model_client.xai_client import XAIClient 24 | from adalflow.utils import setup_env 25 | 26 | setup_env() 27 | 28 | generator = Generator( 29 | model_client=XAIClient(), 30 | model_kwargs={ 31 | "model": "grok-2-latest", 32 | "temperature": 0, 33 | "stream": False, 34 | } 35 | ) 36 | 37 | outpupt = generator(prompt_kwargs={"input_str": "Testing. Just say hi and hello world and nothing else."}) 38 | """ 39 | 40 | def __init__( 41 | self, 42 | api_key: Optional[str] = None, 43 | chat_completion_parser: Callable[[Completion], Any] = None, 44 | input_type: Literal["text", "messages"] = "text", 45 | base_url: str = BASE_URL, 46 | env_api_key_name: str = "XAI_API_KEY", 47 | ): 48 | super().__init__( 49 | api_key=api_key, 50 | chat_completion_parser=chat_completion_parser, 51 | input_type=input_type, 52 | base_url=base_url, 53 | env_api_key_name=env_api_key_name, 54 | ) 55 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/output_parsers/__init__.py: -------------------------------------------------------------------------------- 1 | from .outputs import ( 2 | YamlOutputParser, 3 | JsonOutputParser, 4 | ListOutputParser, 5 | YAML_OUTPUT_FORMAT, 6 | JSON_OUTPUT_FORMAT, 7 | LIST_OUTPUT_FORMAT, 8 | ) 9 | from .dataclass_parser import DataClassParser 10 | 11 | __all__ = [ 12 | "YamlOutputParser", 13 | "JsonOutputParser", 14 | "ListOutputParser", 15 | "YAML_OUTPUT_FORMAT", 16 | "JSON_OUTPUT_FORMAT", 17 | "LIST_OUTPUT_FORMAT", 18 | "DataClassParser", 19 | ] 20 | -------------------------------------------------------------------------------- /adalflow/adalflow/components/retriever/__init__.py: -------------------------------------------------------------------------------- 1 | from .bm25_retriever import ( 2 | BM25Retriever, 3 | split_text_by_word_fn, 4 | split_text_by_word_fn_then_lower_tokenized, 5 | ) 6 | from .llm_retriever import LLMRetriever 7 | 8 | from adalflow.utils import LazyImport, OptionalPackages 9 | from adalflow.utils.registry import EntityMapping 10 | 11 | FAISSRetriever = LazyImport( 12 | "adalflow.components.retriever.faiss_retriever.FAISSRetriever", 13 | OptionalPackages.FAISS, 14 | ) 15 | 16 | from .reranker_retriever import RerankerRetriever 17 | 18 | # from .postgres_retriever import PostgresRetriever 19 | 20 | PostgresRetriever = LazyImport( 21 | "adalflow.components.retriever.postgres_retriever.PostgresRetriever", 22 | OptionalPackages.SQLALCHEMY, 23 | ) 24 | 25 | QdrantRetriever = LazyImport( 26 | "adalflow.components.retriever.qdrant_retriever.QdrantRetriever", 27 | OptionalPackages.QDRANT, 28 | ) 29 | 30 | LanceDBRetriever = LazyImport( 31 | "adalflow.components.retriever.lancedb_retriver.LanceDBRetriever", 32 | OptionalPackages.LANCEDB, 33 | ) 34 | 35 | __all__ = [ 36 | "BM25Retriever", 37 | "LLMRetriever", 38 | "FAISSRetriever", 39 | "RerankerRetriever", 40 | "PostgresRetriever", 41 | "QdrantRetriever", 42 | "LanceDBRetriever", 43 | "split_text_by_word_fn", 44 | "split_text_by_word_fn_then_lower_tokenized", 45 | ] 46 | 47 | 48 | for name in __all__: 49 | EntityMapping.register(name, globals()[name]) 50 | -------------------------------------------------------------------------------- /adalflow/adalflow/core/default_prompt_template.py: -------------------------------------------------------------------------------- 1 | """This is the default system prompt template used in the AdalFlow. 2 | 3 | Use :ref:`Prompt ` class to manage it. 4 | """ 5 | 6 | __all__ = [ 7 | "ADALFLOW_DEFAULT_PROMPT_ARGS", 8 | "ADALFLOW_DEFAULT_PROMPT_TRAINABLE_PARAMS", 9 | "SIMPLE_DEFAULT_ADALFLOW_SYSTEM_PROMPT", 10 | "DEFAULT_ADALFLOW_SYSTEM_PROMPT", 11 | ] 12 | # TODO: potentially make a data class for this 13 | ADALFLOW_DEFAULT_PROMPT_ARGS = [ 14 | "task_desc_str", # task description 15 | "output_format_str", # output format of the task 16 | "tools_str", # tools used in the task 17 | "examples_str", # examples of the task 18 | "chat_history_str", # chat history of the user 19 | "context_str", # context of the user query 20 | "steps_str", # used in agent steps 21 | "input_str", # user query or input 22 | ] 23 | 24 | ADALFLOW_DEFAULT_PROMPT_TRAINABLE_PARAMS = [ 25 | "task_desc_str", 26 | # "output_format_str", 27 | "examples_str", 28 | ] 29 | 30 | SIMPLE_DEFAULT_ADALFLOW_SYSTEM_PROMPT = r"""{{task_desc_str}} 31 | User: {{input_str}} 32 | You:""" 33 | 34 | DEFAULT_ADALFLOW_SYSTEM_PROMPT = r""" 35 | {# task desc #} 36 | {% if task_desc_str %} 37 | {{task_desc_str}} 38 | {% else %} 39 | You are a helpful assistant. 40 | {% endif %} 41 | {#input format#} 42 | {% if input_format_str %} 43 | 44 | {{input_format_str}} 45 | 46 | {% endif %} 47 | {# output format #} 48 | {% if output_format_str %} 49 | 50 | {{output_format_str}} 51 | 52 | {% endif %} 53 | {# tools #} 54 | {% if tools_str %} 55 | 56 | {{tools_str}} 57 | 58 | {% endif %} 59 | {# example #} 60 | {% if examples_str %} 61 | 62 | {{examples_str}} 63 | 64 | {% endif %} 65 | {# chat history #} 66 | {% if chat_history_str %} 67 | 68 | {{chat_history_str}} 69 | 70 | {% endif %} 71 | {#contex#} 72 | {% if context_str %} 73 | 74 | {{context_str}} 75 | 76 | {% endif %} 77 | 78 | 79 | {% if input_str %} 80 | {{input_str}} 81 | {% endif %} 82 | 83 | {# steps #} 84 | {% if steps_str %} 85 | 86 | {{steps_str}} 87 | 88 | {% endif %} 89 | """ 90 | """This is the default system prompt template used in the AdalFlow. 91 | 92 | Use :ref:`Prompt ` class to manage it. 93 | """ 94 | -------------------------------------------------------------------------------- /adalflow/adalflow/core/tokenizer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tokenizer from tiktoken. 3 | """ 4 | 5 | import tiktoken 6 | from typing import List 7 | 8 | # from adalflow.core.component import BaseComponent 9 | 10 | 11 | class Tokenizer: 12 | __doc__ = r""" 13 | Tokenizer component that wraps around the tokenizer from tiktoken. 14 | __call__ is the same as forward/encode, so that we can use it in Sequential 15 | Additonally, you can can also use encode and decode methods. 16 | 17 | Args: 18 | name (str, optional): The name of the tokenizer. Defaults to "cl100k_base". You can find more information 19 | at the tiktoken documentation. 20 | """ 21 | 22 | def __init__(self, name: str = "cl100k_base", remove_stop_words: bool = False): 23 | super().__init__() 24 | self.name = name 25 | self.tokenizer = tiktoken.get_encoding(name) 26 | self.stop_words = ( 27 | set(["and", "the", "is", "in", "at", "of", "a", "an"]) 28 | if remove_stop_words 29 | else set() 30 | ) 31 | 32 | # call is the same as forward/encode, so that we can use it in Sequential 33 | def __call__(self, input: str) -> List[str]: 34 | return self.encode(input) 35 | 36 | def preprocess(self, text: str) -> List[str]: 37 | # Lowercase the text 38 | words = text.lower().split() 39 | return words 40 | 41 | def encode(self, text: str) -> List[int]: 42 | r"""Encodes the input text/word into token IDs.""" 43 | return self.tokenizer.encode(text) 44 | 45 | def decode(self, tokens: List[str]) -> str: 46 | r"""Decodes the input tokens into text.""" 47 | return self.tokenizer.decode(tokens) 48 | 49 | def count_tokens(self, text: str) -> int: 50 | r"""Counts the number of tokens in the input text.""" 51 | return len(self.encode(text)) 52 | 53 | def get_string_tokens(self, text: str) -> List[str]: 54 | r"""Returns the string tokens from the input text.""" 55 | token_ids = self.encode(text) 56 | return [self.tokenizer.decode([token_id]) for token_id in token_ids] 57 | -------------------------------------------------------------------------------- /adalflow/adalflow/database/README.md: -------------------------------------------------------------------------------- 1 | This is where we show how we can leverage cloud db such as postgres along with its vector extension to store and query data. 2 | -------------------------------------------------------------------------------- /adalflow/adalflow/database/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/adalflow/database/__init__.py -------------------------------------------------------------------------------- /adalflow/adalflow/database/sqlalchemy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/adalflow/database/sqlalchemy/__init__.py -------------------------------------------------------------------------------- /adalflow/adalflow/database/sqlalchemy/base.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.declarative import declarative_base 2 | 3 | Base = declarative_base() 4 | -------------------------------------------------------------------------------- /adalflow/adalflow/database/sqlalchemy/pipeline/__init__.py: -------------------------------------------------------------------------------- 1 | "A text splitting and text embedding pipeline using sqlalchemy" 2 | -------------------------------------------------------------------------------- /adalflow/adalflow/database/sqlalchemy/pipeline/create_tables.py: -------------------------------------------------------------------------------- 1 | from adalflow.database.sqlalchemy.sqlachemy_manager import DatabaseManager 2 | 3 | # we need to import the DocumentModel class to create the tables 4 | from adalflow.database.sqlalchemy.model import DocumentModel # noqa 5 | 6 | 7 | if __name__ == "__main__": 8 | db_name = "vector_db" 9 | postgres_url = f"postgresql://postgres:password@localhost:5432/{db_name}" 10 | 11 | db_manager = DatabaseManager(postgres_url) 12 | db_manager.create_tables() 13 | print(db_manager.list_table_schemas()) 14 | db_manager.close() 15 | -------------------------------------------------------------------------------- /adalflow/adalflow/database/sqlalchemy/pipeline/default_config.py: -------------------------------------------------------------------------------- 1 | default_config = { 2 | "document_splitter": { 3 | "component_name": "DocumentSplitter", 4 | "component_config": { 5 | "split_by": "word", 6 | "split_length": 500, 7 | "split_overlap": 200, 8 | }, 9 | }, 10 | "to_embeddings": { 11 | "component_name": "ToEmbeddings", 12 | "component_config": { 13 | "embedder": { 14 | "component_name": "Embedder", 15 | "component_config": { 16 | "model_client": { 17 | "component_name": "OpenAIClient", 18 | "component_config": {}, 19 | }, 20 | "model_kwargs": { 21 | "model": "text-embedding-3-small", 22 | "dimensions": 256, 23 | "encoding_format": "float", 24 | }, 25 | }, 26 | }, 27 | "batch_size": 100, 28 | }, 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /adalflow/adalflow/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | from .big_bench_hard import BigBenchHard 2 | from .hotpot_qa import HotPotQA 3 | from .trec import TrecDataset 4 | from .types import Example, HotPotQAData, TrecData, GSM8KData 5 | from .gsm8k import GSM8K 6 | 7 | __all__ = [ 8 | "BigBenchHard", 9 | "HotPotQA", 10 | "Example", 11 | "HotPotQAData", 12 | "TrecDataset", 13 | "TrecData", 14 | "GSM8KData", 15 | "GSM8K", 16 | ] 17 | -------------------------------------------------------------------------------- /adalflow/adalflow/datasets/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | from adalflow.utils.global_config import get_adalflow_default_root_path 3 | 4 | 5 | def prepare_dataset_path(root: str, task_name: str) -> str: 6 | if root is None: 7 | root = os.path.join(get_adalflow_default_root_path(), "cache_datasets") 8 | 9 | save_path = os.path.join(root, task_name) 10 | os.makedirs(save_path, exist_ok=True) 11 | return save_path 12 | -------------------------------------------------------------------------------- /adalflow/adalflow/eval/__init__.py: -------------------------------------------------------------------------------- 1 | from .answer_match_acc import AnswerMatchAcc 2 | from .retriever_recall import RetrieverEvaluator 3 | from .llm_as_judge import LLMasJudge, DEFAULT_LLM_EVALUATOR_PROMPT 4 | from .g_eval import ( 5 | GEvalJudgeEvaluator, 6 | GEvalLLMJudge, 7 | GEvalMetric, 8 | DEFAULT_G_EVAL_RPROMPT, 9 | ) 10 | 11 | __all__ = [ 12 | "AnswerMatchAcc", 13 | "RetrieverEvaluator", 14 | "LLMasJudge", 15 | "DEFAULT_LLM_EVALUATOR_PROMPT", 16 | "GEvalJudgeEvaluator", 17 | "GEvalLLMJudge", 18 | "GEvalMetric", 19 | "DEFAULT_G_EVAL_RPROMPT", 20 | ] 21 | -------------------------------------------------------------------------------- /adalflow/adalflow/eval/base.py: -------------------------------------------------------------------------------- 1 | """Abstract base class for evaluation metrics.""" 2 | 3 | from typing import Optional, List, Any 4 | 5 | from dataclasses import dataclass 6 | 7 | 8 | @dataclass 9 | class EvaluationResult: 10 | """Evaluation result.""" 11 | 12 | avg_score: float 13 | per_item_scores: Optional[List[float]] = None 14 | additional_info: Optional[dict] = None 15 | 16 | 17 | class BaseEvaluator: 18 | def __init__(self, *args, **kwargs): 19 | pass 20 | 21 | def compute_single_item(self, *args, **kwargs) -> float: 22 | """Compute the score for a single item.""" 23 | raise NotImplementedError("Subclasses must implement this method.") 24 | 25 | # TODO: support multi-threading or async to speed up evaluation 26 | def compute(self, *args, **kwargs) -> Any: 27 | """Evaluate a list of predictions and ground truth values. and return overall score and per-item scores.""" 28 | raise NotImplementedError("Subclasses must implement this method.") 29 | 30 | def __call__(self, *args, **kwargs): 31 | return self.compute(*args, **kwargs) 32 | -------------------------------------------------------------------------------- /adalflow/adalflow/eval/utils.py: -------------------------------------------------------------------------------- 1 | # from hotpotqa github 2 | import re 3 | 4 | import string 5 | from collections import Counter 6 | 7 | 8 | def normalize_answer(s): 9 | 10 | def remove_articles(text): 11 | return re.sub(r"\b(a|an|the)\b", " ", text) 12 | 13 | def white_space_fix(text): 14 | return " ".join(text.split()) 15 | 16 | def remove_punc(text): 17 | exclude = set(string.punctuation) 18 | return "".join(ch for ch in text if ch not in exclude) 19 | 20 | def lower(text): 21 | return text.lower() 22 | 23 | return white_space_fix(remove_articles(remove_punc(lower(s)))) 24 | 25 | 26 | def f1_score(y: str, y_gt: str) -> float: 27 | if not isinstance(y, str) or not isinstance(y_gt, str): 28 | raise ValueError(f"y: {y},{type(y)}, y_gt: {y_gt},{type(y_gt)} must be string.") 29 | prediction_tokens = normalize_answer(y).split() 30 | ground_truth_tokens = normalize_answer(y_gt).split() 31 | 32 | common = Counter(prediction_tokens) & Counter(ground_truth_tokens) 33 | num_same = sum(common.values()) 34 | 35 | if len(prediction_tokens) == len(ground_truth_tokens) == 0: 36 | # Unlike most tasks, QReCC and SQuAD-2.0 assign 1.0 in this edge case. We don't for uniformity. 37 | print( 38 | "\n#> F1 Metric: Rare edge case of len(prediction_tokens) == len(ground_truth_tokens) == 0.\n" 39 | ) 40 | 41 | if num_same == 0: 42 | return 0 43 | 44 | precision = 1.0 * num_same / len(prediction_tokens) 45 | recall = 1.0 * num_same / len(ground_truth_tokens) 46 | f1 = (2 * precision * recall) / (precision + recall) 47 | 48 | return f1 49 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/__init__.py: -------------------------------------------------------------------------------- 1 | from .optimizer import Optimizer 2 | from .sampler import RandomSampler, ClassSampler, Sampler 3 | from .parameter import Parameter, OutputParameter 4 | from .function import BackwardContext 5 | from .few_shot.bootstrap_optimizer import BootstrapFewShot 6 | from .text_grad.tgd_optimizer import TGDOptimizer 7 | from .text_grad.text_loss_with_eval_fn import EvalFnToTextLoss 8 | from .text_grad.llm_text_loss import LLMAsTextLoss 9 | from .trainer.trainer import Trainer 10 | from .trainer.adal import AdalComponent 11 | from adalflow.utils.registry import EntityMapping 12 | from .optimizer import DemoOptimizer, TextOptimizer 13 | from .gradient import Gradient, GradientContext 14 | 15 | 16 | __all__ = [ 17 | "Optimizer", 18 | "RandomSampler", 19 | "ClassSampler", 20 | "Sampler", 21 | "Parameter", 22 | "OutputParameter", 23 | "BackwardContext", 24 | "BootstrapFewShot", 25 | "TGDOptimizer", 26 | "EvalFnToTextLoss", 27 | "LLMAsTextLoss", 28 | "Trainer", 29 | "AdalComponent", 30 | "Optimizer", 31 | "DemoOptimizer", 32 | "TextOptimizer", 33 | "Gradient", 34 | "GradientContext", 35 | ] 36 | 37 | for name in __all__: 38 | EntityMapping.register(name, globals()[name]) 39 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/few_shot/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/adalflow/optim/few_shot/__init__.py -------------------------------------------------------------------------------- /adalflow/adalflow/optim/function.py: -------------------------------------------------------------------------------- 1 | """Inspired by TextGrad: Automatic differentiation via "text" """ 2 | 3 | from typing import TYPE_CHECKING, Callable 4 | 5 | 6 | if TYPE_CHECKING: 7 | from adalflow.core.generator import BackwardEngine 8 | 9 | 10 | class BackwardContext: 11 | """ 12 | Represents a context for backward computation. 13 | 14 | :param backward_fn: The backward function to be called during backward computation. 15 | :type backward_fn: callable 16 | :param args: Variable length argument list to be passed to the backward function. 17 | :param kwargs: Arbitrary keyword arguments to be passed to the backward function. 18 | 19 | :ivar backward_fn: The backward function to be called during backward computation. 20 | :vartype backward_fn: callable 21 | :ivar fn_name: The fully qualified name of the backward function. 22 | :vartype fn_name: str 23 | :ivar args: Variable length argument list to be passed to the backward function. 24 | :ivar kwargs: Arbitrary keyword arguments to be passed to the backward function. 25 | 26 | :method __call__(backward_engine: EngineLM) -> Any: 27 | Calls the backward function with the given backward engine and returns the result. 28 | :method __repr__() -> str: 29 | Returns a string representation of the BackwardContext object. 30 | """ 31 | 32 | def __init__( 33 | self, 34 | disable_backward_engine: bool, 35 | backward_fn: Callable, 36 | backward_engine: "BackwardEngine" = None, 37 | *args, 38 | **kwargs, 39 | ): 40 | self.backward_fn = backward_fn 41 | self.disable_backward_engine = disable_backward_engine 42 | self.backward_engine = backward_engine 43 | self.fn_name = f"{backward_fn.__module__}.{backward_fn.__qualname__}" 44 | self.args = args 45 | self.kwargs = kwargs 46 | 47 | def __call__(self): 48 | if self.backward_engine is None: 49 | return self.backward_fn(*self.args, **self.kwargs) 50 | 51 | return self.backward_fn( 52 | *self.args, 53 | **self.kwargs, 54 | backward_engine=self.backward_engine, 55 | disable_backward_engine=self.disable_backward_engine, 56 | ) 57 | 58 | def __repr__(self): 59 | return f"{self.fn_name}" 60 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/loss_component.py: -------------------------------------------------------------------------------- 1 | """Base class for Autograd Components that can be called and backpropagated through.""" 2 | 3 | from typing import TYPE_CHECKING 4 | import uuid 5 | 6 | if TYPE_CHECKING: 7 | from adalflow.core.generator import BackwardEngine 8 | from adalflow.optim.parameter import Parameter 9 | 10 | from adalflow.core.component import Component 11 | 12 | 13 | # TODO: make it a subclass of GradComponent 14 | class LossComponent(Component): 15 | __doc__ = """A base class to define a loss component. 16 | 17 | Loss component is to compute the textual gradients/feedback for each of its predecessors using another LLM as the backward engine. 18 | 19 | Each precessor should have basic information that is passed to its next component to inform its type such as retriever or generator and its role description. 20 | 21 | Compared with `Component`, `GradComponent` defines three important interfaces: 22 | - `forward`: the forward pass of the function, returns a `Parameter` object that can be traced and backpropagated. 23 | - `backward`: the backward pass of the function, updates the gradients/prediction score backpropagated from a "loss" parameter. 24 | - `set_backward_engine`: set the backward engine(a form of generator) to the component, which is used to backpropagate the gradients. 25 | 26 | The __call__ method will check if the component is in training mode, 27 | and call the `forward` method to return a `Parameter` object if it is in training mode, 28 | otherwise, it will call the `call` method to return the output such as "GeneratorOutput", "RetrieverOutput", etc. 29 | """ 30 | backward_engine: "BackwardEngine" 31 | _component_type = "loss" 32 | id = None 33 | _disable_backward_engine: bool 34 | 35 | def __init__(self, *args, **kwargs): 36 | super().__init__() 37 | super().__setattr__("backward_engine", None) 38 | super().__setattr__("id", str(uuid.uuid4())) 39 | super().__setattr__("_disable_backward_engine", False) 40 | 41 | def __call__(self, *args, **kwargs): 42 | return self.forward(*args, **kwargs) 43 | 44 | def set_backward_engine(self, backward_engine: "BackwardEngine", *args, **kwargs): 45 | raise NotImplementedError("set_backward_engine method is not implemented") 46 | 47 | def disable_backward_engine(self): 48 | r"""Does not run gradients generation, but still with backward to gain module-context""" 49 | self._disable_backward_engine = True 50 | 51 | def forward(self, *args, **kwargs) -> "Parameter": 52 | r"""Default just wraps the call method.""" 53 | raise NotImplementedError("forward method is not implemented") 54 | 55 | def backward(self, *args, **kwargs): 56 | raise NotImplementedError("backward method is not implemented") 57 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/text_grad/__init__.py: -------------------------------------------------------------------------------- 1 | from .llm_text_loss import LLMAsTextLoss 2 | from .tgd_optimizer import TGDOptimizer 3 | from .text_loss_with_eval_fn import EvalFnToTextLoss 4 | from .ops import sum_ops, Sum 5 | 6 | from adalflow.utils.registry import EntityMapping 7 | 8 | __all__ = [ 9 | "LLMAsTextLoss", 10 | "EvalFnToTextLoss", 11 | "TGDOptimizer", 12 | "sum_ops", 13 | "Sum", 14 | ] 15 | 16 | for name in __all__: 17 | EntityMapping.register(name, globals()[name]) 18 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/text_grad/llm_text_loss.py: -------------------------------------------------------------------------------- 1 | """Implementation of TextGrad: Automatic “Differentiation” via Text. 2 | This code is not used as we treat the non-optimizable version of LLM judge as a form of eval_fn. 3 | We use class EvalFnToTextLoss instead as of today 12/9/2024""" 4 | 5 | from typing import Union, TYPE_CHECKING 6 | 7 | if TYPE_CHECKING: 8 | from adalflow.core import ModelClient 9 | from ..parameter import Parameter 10 | 11 | 12 | from adalflow.optim.loss_component import LossComponent 13 | from typing import Dict 14 | from copy import deepcopy 15 | import logging 16 | 17 | log = logging.getLogger(__name__) 18 | 19 | 20 | TEXT_LOSS_TEMPLATE = r""" 21 | {{eval_system_prompt}} 22 | 23 | 24 | {{eval_user_prompt}} 25 | 26 | """ 27 | 28 | 29 | class LLMAsTextLoss(LossComponent): 30 | __doc__ = r"""Evaluate the final RAG response using an LLM judge. 31 | 32 | The LLM judge will have: 33 | - eval_system_prompt: The system prompt to evaluate the response. 34 | - y_hat: The response to evaluate. 35 | - Optional: y: The correct response to compare against. 36 | 37 | The loss will be a Parameter with the evaluation result and can be used to compute gradients. 38 | This loss use LLM/Generator as the computation/transformation operator, so it's gradient will be 39 | found from the Generator's backward method. 40 | """ 41 | 42 | def __init__( 43 | self, 44 | prompt_kwargs: Dict[str, Union[str, "Parameter"]], 45 | model_client: "ModelClient", 46 | model_kwargs: Dict[str, object], 47 | ): 48 | from adalflow.core.generator import Generator 49 | from adalflow.optim.parameter import Parameter 50 | 51 | super().__init__() 52 | prompt_kwargs = deepcopy(prompt_kwargs) 53 | # TODO: do we really need to convert str to Parameter? what if not? 54 | for key, value in prompt_kwargs.items(): 55 | if isinstance(value, str): 56 | prompt_kwargs[key] = Parameter( 57 | data=value, requires_opt=False, role_desc=key 58 | ) 59 | self.prompt_kwargs = prompt_kwargs 60 | # this is llm as judge (loss) to get the loss 61 | self.loss_llm = Generator( 62 | name="llm_judge", 63 | model_client=model_client, 64 | model_kwargs=model_kwargs, 65 | template=TEXT_LOSS_TEMPLATE, 66 | prompt_kwargs=prompt_kwargs, 67 | ) 68 | 69 | # def __call__(self, *args, **kwargs): 70 | # return self.forward(*args, **kwargs) 71 | 72 | def forward(self, *args, **kwargs) -> "Parameter": 73 | 74 | return self.loss_llm.forward(*args, **kwargs) 75 | -------------------------------------------------------------------------------- /adalflow/adalflow/optim/trainer/__init__.py: -------------------------------------------------------------------------------- 1 | from .trainer import Trainer 2 | from .adal import AdalComponent 3 | from adalflow.utils.registry import EntityMapping 4 | 5 | 6 | __all__ = [ 7 | "Trainer", 8 | "AdalComponent", 9 | ] 10 | for name in __all__: 11 | EntityMapping.register(name, globals()[name]) 12 | -------------------------------------------------------------------------------- /adalflow/adalflow/tracing/__init__.py: -------------------------------------------------------------------------------- 1 | from .generator_state_logger import GeneratorStateLogger 2 | from .generator_call_logger import GeneratorCallLogger 3 | from .decorators import trace_generator_states, trace_generator_call 4 | 5 | __all__ = [ 6 | "trace_generator_states", 7 | "trace_generator_call", 8 | "GeneratorStateLogger", 9 | "GeneratorCallLogger", 10 | ] 11 | -------------------------------------------------------------------------------- /adalflow/adalflow/tracing/callback_manager.py: -------------------------------------------------------------------------------- 1 | """A simple callback manager for tracing Geneator calls""" 2 | 3 | from typing import Callable, Literal 4 | 5 | 6 | class CallbackManager: 7 | def __init__(self): 8 | self.callbacks = { 9 | "on_success": [], 10 | "on_failure": [], 11 | "on_complete": [], # You can define more event types as needed. 12 | } 13 | 14 | def register_callback( 15 | self, 16 | event_type: Literal["on_success", "on_failure", "on_complete"], 17 | callback: Callable, 18 | ): 19 | """Register a callback for a specific event type.""" 20 | if event_type in self.callbacks: 21 | self.callbacks[event_type].append(callback) 22 | else: 23 | raise ValueError(f"Unsupported event type: {event_type}") 24 | 25 | def trigger_callbacks( 26 | self, 27 | event_type: Literal["on_success", "on_failure", "on_complete"], 28 | *args, 29 | **kwargs, 30 | ): 31 | """Invoke all callbacks for a given event type.""" 32 | if event_type in self.callbacks: 33 | for callback in self.callbacks[event_type]: 34 | callback(*args, **kwargs) 35 | else: 36 | raise ValueError(f"Unsupported event type: {event_type}") 37 | -------------------------------------------------------------------------------- /adalflow/adalflow/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .serialization import ( 2 | default, 3 | serialize, 4 | deserialize, 5 | ) 6 | from .file_io import ( 7 | save_json, 8 | load_json, 9 | save_pickle, 10 | load_pickle, 11 | save, 12 | load, 13 | load_jsonl, 14 | append_to_jsonl, 15 | write_list_to_jsonl, 16 | ) 17 | from .logger import printc, get_logger 18 | from .registry import EntityMapping 19 | from .config import new_components_from_config, new_component 20 | from .lazy_import import LazyImport, OptionalPackages, safe_import 21 | from .setup_env import setup_env 22 | from .data import DataLoader, Dataset, Subset 23 | from .global_config import get_adalflow_default_root_path 24 | from .cache import CachedEngine 25 | 26 | 27 | __all__ = [ 28 | "save", 29 | "load", 30 | "printc", 31 | "get_logger", 32 | "EntityMapping", 33 | "new_components_from_config", 34 | "LazyImport", 35 | "OptionalPackages", 36 | "new_component", 37 | "default", 38 | "serialize", 39 | "deserialize", 40 | "save_json", 41 | "load_json", 42 | "save_pickle", 43 | "load_pickle", 44 | "load_jsonl", 45 | "append_to_jsonl", 46 | "write_list_to_jsonl", 47 | "safe_import", 48 | "setup_env", 49 | "DataLoader", 50 | "Dataset", 51 | "Subset", 52 | "get_adalflow_default_root_path", 53 | "CachedEngine", 54 | ] 55 | -------------------------------------------------------------------------------- /adalflow/adalflow/utils/cache.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import diskcache as dc 3 | from pathlib import Path 4 | from typing import Union 5 | 6 | 7 | def hash_text(text: str): 8 | return hashlib.sha256(f"{text}".encode()).hexdigest() 9 | 10 | 11 | def hash_text_sha1(text: str): # 160 bits 12 | return hashlib.sha1(text.encode()).hexdigest() 13 | 14 | 15 | def direct(text: str): 16 | return text 17 | 18 | 19 | class CachedEngine: 20 | def __init__(self, cache_path: Union[str, Path]): 21 | super().__init__() 22 | self.cache_path = Path(cache_path) 23 | self.cache_path.parent.mkdir(parents=True, exist_ok=True) 24 | 25 | self.cache = dc.Cache(cache_path) 26 | 27 | def _check_cache(self, prompt: str): 28 | hash_key = hash_text(prompt) 29 | if hash_key in self.cache: 30 | return self.cache[hash_key] 31 | else: 32 | return None 33 | 34 | def _save_cache(self, prompt: str, response: str): 35 | hash_key = hash_text(prompt) 36 | self.cache[hash_key] = response 37 | 38 | def __getstate__(self): 39 | # Remove the cache from the state before pickling 40 | state = self.__dict__.copy() 41 | del state["cache"] 42 | return state 43 | 44 | def __setstate__(self, state): 45 | # Restore the cache after unpickling 46 | self.__dict__.update(state) 47 | self.cache = dc.Cache(self.cache_path) 48 | -------------------------------------------------------------------------------- /adalflow/adalflow/utils/global_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | def get_adalflow_default_root_path() -> str: 6 | r"""This will be used for storing datasets, cache, logs, trained models, etc.""" 7 | root = None 8 | if sys.platform == "win32": 9 | root = os.path.join(os.getenv("APPDATA"), "adalflow") 10 | else: 11 | root = os.path.join(os.path.expanduser("~"), ".adalflow") 12 | return root 13 | -------------------------------------------------------------------------------- /adalflow/adalflow/utils/registry.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Type 2 | 3 | 4 | class EntityMapping: 5 | __doc__ = r"""A registry for entities, components,classes, function. 6 | 7 | This can be used to configure classes, functions, or components in a registry. 8 | """ 9 | _registry: Dict[str, Type] = {} 10 | 11 | @classmethod 12 | def register(cls, name: str, entity_cls: Type): 13 | cls._registry[name] = entity_cls 14 | 15 | @classmethod 16 | def get(cls, name: str) -> Type: 17 | return cls._registry[name] if name in cls._registry else None 18 | 19 | @classmethod 20 | def get_all(cls) -> Dict[str, Type]: 21 | return cls._registry 22 | -------------------------------------------------------------------------------- /adalflow/adalflow/utils/setup_env.py: -------------------------------------------------------------------------------- 1 | import dotenv 2 | import os 3 | import logging 4 | 5 | log = logging.getLogger(__name__) 6 | 7 | 8 | def setup_env(dotenv_path: str = ".env"): 9 | """Load environment variables from .env file.""" 10 | 11 | if not os.path.exists(dotenv_path): 12 | raise FileNotFoundError(f"File not found: {dotenv_path}") 13 | 14 | try: 15 | dotenv.load_dotenv(dotenv_path=dotenv_path, verbose=True, override=False) 16 | except Exception as e: 17 | log.error(f"Error loading .env file: {e}") 18 | raise e 19 | -------------------------------------------------------------------------------- /adalflow/pytest.ini: -------------------------------------------------------------------------------- 1 | # pytest.ini 2 | [pytest] 3 | python_files = test_*.py 4 | python_classes = Test* 5 | python_functions = test_* 6 | norecursedirs = *_test 7 | -------------------------------------------------------------------------------- /adalflow/tests/README.md: -------------------------------------------------------------------------------- 1 | 2 | #Setup 3 | Install the required packages: 4 | ``` 5 | poetry install --with test 6 | ``` 7 | 8 | 1. Run `pytest` for all tests. 9 | 2. Run all tests in a specific file: 10 | ``` 11 | pytest tests/test_file.py 12 | ``` 13 | 1. Run a specific test function or class and even its methods within a class: 14 | ``` 15 | pytest tests/test_file.py::test_function 16 | ``` 17 | 1. Run a specific test with verbose output: 18 | ``` 19 | pytest tests/test_file.py::test_function -v -s 20 | ``` 21 | 1. Run a specific test with verbose output and show local variables: 22 | ``` 23 | pytest tests/test_file.py::test_function -vv 24 | ``` 25 | 1. Run a specific test with verbose output and show local variables and capture output: 26 | ``` 27 | pytest tests/test_file.py::test_function -vv -s 28 | ``` 29 | 30 | # About API keys 31 | For test, we dont pass the real API keys. We use the `pytest` library to mock the API keys. 32 | 33 | In the action workflow, we use the `secrets` to pass the test API keys. 34 | -------------------------------------------------------------------------------- /adalflow/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/adalflow/tests/__init__.py -------------------------------------------------------------------------------- /adalflow/tests/test_data_classes.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from uuid import uuid4 3 | 4 | from adalflow.core.types import ( 5 | UserQuery, 6 | AssistantResponse, 7 | DialogTurn, 8 | Conversation, 9 | ) 10 | 11 | 12 | def test_user_query_creation(): 13 | query = "What is the weather today?" 14 | metadata = {"location": "New York"} 15 | user_query = UserQuery(query_str=query, metadata=metadata) 16 | assert user_query.query_str == query 17 | assert user_query.metadata == metadata 18 | 19 | 20 | def test_assistant_response_creation(): 21 | response = "It's sunny in New York today." 22 | metadata = {"temperature": "75°F"} 23 | assistant_response = AssistantResponse(response_str=response, metadata=metadata) 24 | assert assistant_response.response_str == response 25 | assert assistant_response.metadata == metadata 26 | 27 | 28 | def test_dialog_turn_creation(): 29 | user_query = UserQuery(query_str="Hello, how are you?") 30 | assistant_response = AssistantResponse(response_str="I'm fine, thank you!") 31 | dialog_turn = DialogTurn( 32 | id=str(uuid4()), user_query=user_query, assistant_response=assistant_response 33 | ) 34 | assert dialog_turn.user_query == user_query 35 | assert dialog_turn.assistant_response == assistant_response 36 | assert isinstance(dialog_turn.id, str) 37 | 38 | 39 | def test_dialog_session_operations(): 40 | session = Conversation() 41 | assert isinstance(session.id, str) # Check if the UUID is automatically generated 42 | 43 | # Creating dialog turns 44 | user_query = UserQuery(query_str="Hello, how are you?") 45 | assistant_response = AssistantResponse(response_str="I'm fine, thank you!") 46 | dialog_turn = DialogTurn( 47 | id=str(uuid4()), user_query=user_query, assistant_response=assistant_response 48 | ) 49 | 50 | session.append_dialog_turn(dialog_turn) 51 | assert len(session.dialog_turns) == 1 52 | assert ( 53 | session.dialog_turns[0] == dialog_turn 54 | ), f"Expected {session.dialog_turns} in session." 55 | 56 | # Testing order enforcement 57 | with pytest.raises(AssertionError): 58 | wrong_turn = DialogTurn( 59 | id=str(uuid4()), 60 | order=2, 61 | user_query=user_query, 62 | assistant_response=assistant_response, 63 | ) 64 | session.append_dialog_turn(wrong_turn) 65 | 66 | # Update and delete operations 67 | new_response = AssistantResponse(response_str="Actually, I'm great!") 68 | updated_turn = DialogTurn( 69 | id=dialog_turn.id, user_query=user_query, assistant_response=new_response 70 | ) 71 | session.update_dialog_turn(1, updated_turn) 72 | assert ( 73 | session.dialog_turns[1].assistant_response.response_str 74 | == "Actually, I'm great!" 75 | ) 76 | 77 | session.delete_dialog_turn(1) 78 | assert len(session.dialog_turns) == 1 79 | -------------------------------------------------------------------------------- /adalflow/tests/test_deepseek_client.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | 4 | from adalflow.components.model_client.deepseek_client import DeepSeekClient 5 | 6 | 7 | def getenv_side_effect(key): 8 | env_vars = {"DEEPSEEK_API_KEY": "fake_api_key"} 9 | return env_vars.get(key, None) 10 | 11 | 12 | class TestDeepSeekClient(unittest.TestCase): 13 | def setUp(self): 14 | self.client = DeepSeekClient(api_key="fake_api_key") 15 | 16 | def test_deepseek_init(self): 17 | self.assertEqual(self.client.base_url, "https://api.deepseek.com/v1/") 18 | self.assertEqual(self.client._input_type, "messages") 19 | self.assertEqual(self.client._env_api_key_name, "DEEPSEEK_API_KEY") 20 | 21 | # mock os.getenv(self._env_api_key_name) with getenv_side_effect 22 | @patch("os.getenv") 23 | def test_deepseek_init_sync_client(self, mock_os_getenv): 24 | mock_os_getenv.return_value = "fake_api_key" 25 | self.client.init_sync_client() 26 | self.assertEqual(self.client.sync_client.api_key, "fake_api_key") 27 | self.assertEqual( 28 | self.client.sync_client.base_url, "https://api.deepseek.com/v1/" 29 | ) 30 | 31 | @patch("os.getenv") 32 | def test_deepseek_init_async_client(self, mock_os_getenv): 33 | mock_os_getenv.return_value = "fake_api_key" 34 | self.client.async_client = self.client.init_async_client() 35 | self.assertEqual(self.client.async_client.api_key, "fake_api_key") 36 | self.assertEqual( 37 | self.client.async_client.base_url, "https://api.deepseek.com/v1/" 38 | ) 39 | 40 | 41 | if __name__ == "__main__": 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /adalflow/tests/test_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from unittest.mock import MagicMock 3 | 4 | from adalflow.utils import get_logger, printc 5 | 6 | 7 | class TestGetDefaultLogger: 8 | def test_console_logging_only(self, mocker): 9 | mocker.patch("os.makedirs") 10 | mock_handler = mocker.patch( 11 | "logging.StreamHandler", return_value=MagicMock(spec=logging.StreamHandler) 12 | ) 13 | 14 | logger = get_logger( 15 | name="test_console_logging_only", enable_file=False, enable_console=True 16 | ) 17 | 18 | assert logger.hasHandlers() 19 | assert mock_handler.called 20 | mock_handler.return_value.setFormatter.assert_called() 21 | 22 | def test_file_logging_only(self, mocker): 23 | mocker.patch("os.makedirs") 24 | mock_file_handler = mocker.patch( 25 | "logging.FileHandler", return_value=MagicMock(spec=logging.FileHandler) 26 | ) 27 | 28 | logger = get_logger( 29 | name="test_file_logging_only", enable_console=False, enable_file=True 30 | ) 31 | 32 | assert logger.hasHandlers() 33 | assert mock_file_handler.called 34 | mock_file_handler.return_value.setFormatter.assert_called() 35 | 36 | def test_both_console_and_file_logging(self, mocker): 37 | mocker.patch("os.makedirs") 38 | mocker.patch( 39 | "logging.StreamHandler", return_value=MagicMock(spec=logging.StreamHandler) 40 | ) 41 | mocker.patch( 42 | "logging.FileHandler", return_value=MagicMock(spec=logging.FileHandler) 43 | ) 44 | 45 | logger = get_logger( 46 | name="test_both_console_and_file_logging", 47 | enable_console=True, 48 | enable_file=True, 49 | ) 50 | 51 | assert logger.hasHandlers() 52 | assert len(logger.handlers) == 2 # Both handlers should be added 53 | 54 | def test_no_logging(self, mocker): 55 | mocker.patch("os.makedirs") 56 | logger = get_logger( 57 | name="test_no_logging", enable_console=False, enable_file=False 58 | ) 59 | 60 | assert not logger.hasHandlers() 61 | 62 | 63 | class TestPrintc: 64 | def test_colored_print(self, mocker): 65 | mocker.patch("builtins.print") 66 | 67 | printc("hello world", color="green") 68 | 69 | assert print.called 70 | args, _ = print.call_args 71 | assert "\x1b[32m" in args[0] # Check if green color code is in the print output 72 | 73 | def test_default_color(self, mocker): 74 | mocker.patch("builtins.print") 75 | 76 | printc("hello world") 77 | 78 | assert print.called 79 | args, _ = print.call_args 80 | assert ( 81 | "\x1b[36m" in args[0] 82 | ) # Check if default cyan color code is in the print output 83 | -------------------------------------------------------------------------------- /adalflow/tests/test_memory.py: -------------------------------------------------------------------------------- 1 | from adalflow.components.memory.memory import Memory 2 | 3 | 4 | def test_empty_memory(): 5 | memory = Memory() 6 | assert memory() == "" 7 | 8 | 9 | def test_add_dialog_turn(): 10 | memory = Memory() 11 | memory.add_dialog_turn("Hello", "Hi! How can I help you?") 12 | expected = "User: Hello\nAssistant: Hi! How can I help you?" 13 | assert memory() == expected 14 | 15 | 16 | def test_multiple_turns(): 17 | memory = Memory() 18 | memory.add_dialog_turn("Hello", "Hi!") 19 | memory.add_dialog_turn("How are you?", "I'm good!") 20 | expected = ( 21 | "User: Hello\n" "Assistant: Hi!\n" "User: How are you?\n" "Assistant: I'm good!" 22 | ) 23 | assert memory() == expected 24 | -------------------------------------------------------------------------------- /adalflow/tests/test_model_client.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | import unittest 3 | from unittest.mock import patch 4 | 5 | from adalflow.components.model_client import OpenAIClient as OpenAIClientLazyImport 6 | from adalflow.components.model_client.openai_client import OpenAIClient 7 | from adalflow.core.types import GeneratorOutput 8 | 9 | 10 | class TestLazyImportSubclassing(unittest.TestCase): 11 | def setUp(self): 12 | self.client = OpenAIClient(api_key="test") 13 | 14 | def test_subclassing_raises_error(self): 15 | with self.assertRaises(TypeError): 16 | 17 | class InvalidCustomizeOpenAIClient(OpenAIClientLazyImport): 18 | def __init__(self): 19 | super().__init__() 20 | 21 | def parse_chat_completion(self, completion: Any) -> Any: 22 | """Parse the completion to a str.""" 23 | print(f"completion: {completion}") 24 | return self.chat_completion_parser(completion) 25 | 26 | InvalidCustomizeOpenAIClient() 27 | 28 | @patch.dict("os.environ", {"OPENAI_API_KEY": "test_api_key"}) 29 | def test_correct_subclassing(self): 30 | from adalflow.components.model_client.openai_client import OpenAIClient 31 | 32 | class CorrectCustomizeOpenAIClient(OpenAIClient): 33 | def __init__(self): 34 | super().__init__() 35 | 36 | def parse_chat_completion(self, completion: Any) -> Any: 37 | """Parse the completion to a str.""" 38 | print(f"completion: {completion}") 39 | return self.chat_completion_parser(completion) 40 | 41 | CorrectCustomizeOpenAIClient() 42 | 43 | @patch.object(OpenAIClient, "parse_chat_completion") 44 | def test_parse_chat_completion(self, mock_parse_chat_completion): 45 | mock_parse_chat_completion.return_value = GeneratorOutput() 46 | result = self.client.parse_chat_completion(completion="completion") 47 | self.assertIsInstance(result, GeneratorOutput) 48 | mock_parse_chat_completion.assert_called_once_with(completion="completion") 49 | 50 | 51 | if __name__ == "__main__": 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /adalflow/tests/test_ollama_client.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import Mock 3 | from adalflow.core.types import ModelType 4 | from adalflow.components.model_client.ollama_client import OllamaClient 5 | 6 | # import ollama 7 | 8 | # Check if ollama model is installed 9 | # def model_installed(model_name: str): 10 | # model_list = ollama.list() 11 | # for model in model_list['models']: 12 | # if model['name'] == model_name: 13 | # return True 14 | # return False 15 | 16 | 17 | class TestOllamaModelClient(unittest.TestCase): 18 | 19 | def test_ollama_llm_client(self): 20 | ollama_client = Mock(spec=OllamaClient()) 21 | print("Testing ollama LLM client") 22 | # run the model 23 | kwargs = { 24 | "model": "qwen2:0.5b", 25 | } 26 | api_kwargs = ollama_client.convert_inputs_to_api_kwargs( 27 | input="Hello world", 28 | model_kwargs=kwargs, 29 | model_type=ModelType.LLM, 30 | ).return_value = {"prompt": "Hello World", "model": "qwen2:0.5b"} 31 | assert api_kwargs == {"prompt": "Hello World", "model": "qwen2:0.5b"} 32 | output = ollama_client.call( 33 | api_kwargs=api_kwargs, model_type=ModelType.LLM 34 | ).return_value = {"message": "Hello"} 35 | assert output == {"message": "Hello"} 36 | 37 | def test_ollama_embedding_client(self): 38 | ollama_client = Mock(spec=OllamaClient()) 39 | print("Testing ollama embedding client") 40 | 41 | # run the model 42 | kwargs = { 43 | "model": "jina/jina-embeddings-v2-base-en:latest", 44 | } 45 | api_kwargs = ollama_client.convert_inputs_to_api_kwargs( 46 | input="Welcome", 47 | model_kwargs=kwargs, 48 | model_type=ModelType.EMBEDDER, 49 | ).return_value = { 50 | "prompt": "Welcome", 51 | "model": "jina/jina-embeddings-v2-base-en:latest", 52 | } 53 | assert api_kwargs == { 54 | "prompt": "Welcome", 55 | "model": "jina/jina-embeddings-v2-base-en:latest", 56 | } 57 | 58 | output = ollama_client.call( 59 | api_kwargs=api_kwargs, model_type=ModelType.EMBEDDER 60 | ).return_value = {"embedding": [-0.7391586899757385]} 61 | assert output == {"embedding": [-0.7391586899757385]} 62 | 63 | 64 | if __name__ == "__main__": 65 | unittest.main() 66 | -------------------------------------------------------------------------------- /adalflow/tests/test_random_sample.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from typing import TypeVar 3 | from adalflow.core.functional import random_sample 4 | 5 | 6 | # Assuming the random_sample function is defined here or imported 7 | T_co = TypeVar("T_co", covariant=True) 8 | 9 | 10 | class TestRandomSample(unittest.TestCase): 11 | 12 | def setUp(self): 13 | """Set up a common dataset for testing.""" 14 | self.dataset = [1, 2, 3, 4, 5] 15 | 16 | def test_random_sample_no_replacement(self): 17 | """Test random sampling without replacement.""" 18 | result = random_sample(self.dataset, 3, replace=False) 19 | self.assertEqual(len(result), 3) 20 | self.assertTrue(all(item in self.dataset for item in result)) 21 | self.assertEqual(len(set(result)), 3) # No duplicates 22 | 23 | def test_random_sample_with_replacement(self): 24 | """Test random sampling with replacement.""" 25 | result = random_sample(self.dataset, 10, replace=True) 26 | self.assertEqual(len(result), 10) 27 | self.assertTrue(all(item in self.dataset for item in result)) 28 | 29 | def test_weighted_sampling_all_zero_weights(self): 30 | """Test weighted sampling with all zero weights.""" 31 | result = random_sample(self.dataset, 3, replace=False, weights=[0, 0, 0, 0, 0]) 32 | self.assertEqual(len(result), 3) 33 | self.assertTrue(all(item in self.dataset for item in result)) 34 | 35 | def test_weights_none(self): 36 | """Test weighted sampling with None weights.""" 37 | result = random_sample(self.dataset, 3, replace=False, weights=None) 38 | self.assertEqual(len(result), 3) 39 | self.assertTrue(all(item in self.dataset for item in result)) 40 | 41 | def test_weighted_sampling_normal_weights(self): 42 | """Test weighted sampling with normal weights.""" 43 | weights = [0.1, 0.2, 0.3, 0.4, 0.0] 44 | result = random_sample(self.dataset, 3, replace=False, weights=weights) 45 | self.assertEqual(len(result), 3) 46 | self.assertTrue(all(item in self.dataset for item in result)) 47 | 48 | 49 | if __name__ == "__main__": 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /adalflow/tests/test_trainer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import MagicMock 3 | 4 | from adalflow.optim.trainer import Trainer, AdalComponent 5 | from adalflow.utils.data import DataLoader 6 | 7 | 8 | class TestTrainer(unittest.TestCase): 9 | def setUp(self): 10 | self.train_loader = DataLoader(dataset=[1, 2, 3, 4, 5], batch_size=2) 11 | 12 | def test_no_train_dataset(self): 13 | trainer = Trainer( 14 | adaltask=MagicMock(spec=AdalComponent), 15 | ) 16 | with self.assertRaises(ValueError): 17 | trainer.fit(train_dataset=None) 18 | 19 | def test_no_val_dataset(self): 20 | trainer = Trainer( 21 | adaltask=MagicMock(spec=AdalComponent), 22 | ) 23 | with self.assertRaises(ValueError): 24 | trainer.fit(train_dataset=[1, 2, 3, 4, 5], val_dataset=None) 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/benchmarks/BHH_object_count/__init__.py -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/dspy_count.py: -------------------------------------------------------------------------------- 1 | import dspy 2 | import re 3 | 4 | turbo = dspy.OpenAI(model="gpt-3.5-turbo") 5 | dspy.settings.configure(lm=turbo) 6 | 7 | 8 | def parse_integer_answer(answer: str): 9 | """A function that parses the last integer from a string using regular expressions.""" 10 | try: 11 | # Use regular expression to find all sequences of digits 12 | numbers = re.findall(r"\d+", answer) 13 | if numbers: 14 | # Get the last number found 15 | answer = int(numbers[-1]) 16 | else: 17 | answer = -1 18 | except ValueError: 19 | answer = -1 20 | 21 | return answer 22 | 23 | 24 | class GenerateAnswer(dspy.Signature): 25 | # NOTE: this doc string acts as the system prompt 26 | """You will answer a reasoning question. Think step by step.""" # The last line of your response should be of the following format: 'Answer: $VALUE' where VALUE is a numerical value.""" 27 | 28 | question = dspy.InputField(desc="The question to be answered") 29 | 30 | answer: str = dspy.OutputField( 31 | desc="The numerical answer, must be an integer." 32 | ) # field can only be str or list of str 33 | 34 | 35 | class ObjectCount(dspy.Module): 36 | def __init__(self): 37 | super().__init__() 38 | 39 | # self.generate_answer = dspy.Predict(GenerateAnswer) 40 | self.generate_answer = dspy.ChainOfThought(GenerateAnswer) 41 | 42 | def forward(self, question): 43 | 44 | pred = self.generate_answer(question=question) 45 | answer = parse_integer_answer(pred.answer) 46 | answer = str(answer) # dspy will assume these fields are strings not integers 47 | # print(f"Pred: {pred}, Answer: {answer}") 48 | return dspy.Prediction(answer=answer) 49 | 50 | 51 | if __name__ == "__main__": 52 | from adalflow.utils import setup_env 53 | 54 | setup_env() 55 | obj = ObjectCount() 56 | question = "I have a flute, a piano, a trombone, four stoves, a violin, an accordion, a clarinet, a drum, two lamps, and a trumpet. How many musical instruments do I have?" 57 | 58 | print(obj(question)) 59 | -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/models/text_grad/sta.py: -------------------------------------------------------------------------------- 1 | training_time = (2005 * 3 + 3056) / 4 2 | test_scores = [0.84, 0.86, 0.79, 0.89] 3 | val_scores = [0.95, 0.97, 0.93, 0.96] 4 | 5 | import numpy as np 6 | 7 | mean_test_score = np.mean(test_scores) 8 | std_test_score = np.std(test_scores) 9 | 10 | # val scores 11 | mean_val_score = np.mean(val_scores) 12 | std_val_score = np.std(val_scores) 13 | 14 | print(f"Mean test score: {mean_test_score}") 15 | print(f"Standard deviation of test scores: {std_test_score}") 16 | print(f"Mean validation score: {mean_val_score}") 17 | print(f"Standard deviation of validation scores: {std_val_score}") 18 | print(f"Average training time: {training_time}") 19 | 20 | # Mean test score: 0.8450000000000001 21 | # Standard deviation of test scores: 0.036400549446402586 22 | # Mean validation score: 0.9525 23 | # Standard deviation of validation scores: 0.014790199457749011 24 | 25 | val_accs = [ 26 | [ 27 | 0.74, 28 | 0.89, 29 | 0.92, 30 | 0.92, 31 | 0.95, 32 | 0.95, 33 | 0.95, 34 | 0.95, 35 | 0.95, 36 | 0.95, 37 | 0.95, 38 | 0.95, 39 | 0.95, 40 | 0.95, 41 | ], 42 | [ 43 | 0.74, 44 | 0.92, 45 | 0.92, 46 | 0.92, 47 | 0.92, 48 | 0.92, 49 | 0.92, 50 | 0.92, 51 | 0.92, 52 | 0.92, 53 | 0.92, 54 | 0.92, 55 | 0.92, 56 | 0.97, 57 | ], 58 | [0.74, 0.87, 0.87, 0.88, 0.88, 0.9, 0.9, 0.9, 0.9, 0.9, 0.91, 0.91, 0.93, 0.93], 59 | [ 60 | 0.74, 61 | 0.85, 62 | 0.91, 63 | 0.91, 64 | 0.91, 65 | 0.91, 66 | 0.91, 67 | 0.91, 68 | 0.91, 69 | 0.91, 70 | 0.91, 71 | 0.91, 72 | 0.96, 73 | 0.96, 74 | ], 75 | ] 76 | 77 | pass_rates = [len(set(val_acc)) / len(val_acc) for val_acc in val_accs] 78 | average_pass_rate = np.mean(pass_rates) 79 | 80 | print(f"Average pass rate: {average_pass_rate}") # 30.35 81 | -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/text_grad/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/benchmarks/BHH_object_count/text_grad/__init__.py -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/text_grad/config.py: -------------------------------------------------------------------------------- 1 | import textgrad as tg 2 | from adalflow.utils import setup_env 3 | 4 | setup_env() 5 | 6 | gpt4o = tg.get_engine(engine_name="gpt-4o") 7 | gpt_3_5 = tg.get_engine(engine_name="gpt-3.5-turbo-0125") 8 | -------------------------------------------------------------------------------- /benchmarks/BHH_object_count/text_grad/src.py: -------------------------------------------------------------------------------- 1 | import random 2 | import concurrent.futures 3 | from tqdm import tqdm 4 | import numpy as np 5 | 6 | import textgrad as tg 7 | 8 | log = tg.logging.getLogger(__name__) 9 | 10 | 11 | def set_seed(seed): 12 | np.random.seed(seed) 13 | random.seed(seed) 14 | 15 | 16 | def eval_sample(item, eval_fn, model): 17 | """ 18 | This function allows us to evaluate if an answer to a question in the prompt is a good answer. 19 | 20 | """ 21 | x, y = item 22 | x = tg.Variable( 23 | x, requires_grad=False, role_description="query to the language model" 24 | ) 25 | y = str(y) 26 | y = tg.Variable( 27 | y, requires_grad=False, role_description="correct answer for the query" 28 | ) 29 | response = model(x) 30 | try: 31 | eval_output_variable = eval_fn( 32 | inputs=dict(prediction=response, ground_truth_answer=y) 33 | ) 34 | return int(eval_output_variable.value) 35 | except Exception as e: 36 | log.info(f"Error: {e}") 37 | eval_output_variable = eval_fn([x, y, response]) 38 | eval_output_parsed = eval_fn.parse_output(eval_output_variable) 39 | return int(eval_output_parsed) 40 | 41 | 42 | def eval_dataset(test_set, eval_fn, model, max_samples: int = None): 43 | if max_samples is None: 44 | max_samples = len(test_set) 45 | accuracy_list = [] 46 | with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: 47 | futures = [] 48 | for _, sample in enumerate(test_set): 49 | print("sample: ", sample) 50 | 51 | future = executor.submit(eval_sample, sample, eval_fn, model) 52 | futures.append(future) 53 | if len(futures) >= max_samples: 54 | break 55 | tqdm_loader = tqdm( 56 | concurrent.futures.as_completed(futures), total=len(futures), position=0 57 | ) 58 | for future in tqdm_loader: 59 | acc_item = future.result() 60 | accuracy_list.append(acc_item) 61 | tqdm_loader.set_description(f"Batch Accuracy: {np.mean(accuracy_list)}") 62 | return accuracy_list 63 | 64 | 65 | # use ours propose if accept, set, if not , revert 66 | def run_validation_revert(system_prompt: tg.Variable, results, model, eval_fn, val_set): 67 | val_performance = np.mean(eval_dataset(val_set, eval_fn, model, max_samples=None)) 68 | previous_performance = np.mean(results["validation_acc"][-1]) 69 | print("val_performance: ", val_performance) 70 | print("previous_performance: ", previous_performance) 71 | previous_prompt = results["prompt"][-1] 72 | 73 | if val_performance < previous_performance: 74 | print(f"rejected prompt: {system_prompt.value}") 75 | system_prompt.set_value(previous_prompt) 76 | val_performance = previous_performance 77 | 78 | results["validation_acc"].append(val_performance) 79 | -------------------------------------------------------------------------------- /benchmarks/README.md: -------------------------------------------------------------------------------- 1 | Benchmarking is an integral development part of the project. 2 | 3 | Contributors are encouraged to write benchmarks for their code, besides of the unit tests in `tests/` directory. 4 | -------------------------------------------------------------------------------- /benchmarks/__init__.py: -------------------------------------------------------------------------------- 1 | """Benchmark performance, and potentially compare with other libraries.""" 2 | -------------------------------------------------------------------------------- /benchmarks/config.py: -------------------------------------------------------------------------------- 1 | from adalflow.components.model_client import GroqAPIClient 2 | from adalflow.components.model_client import OpenAIClient 3 | 4 | dspy_save_path = "benchmarks/BHH_object_count/models/dspy" 5 | text_grad_save_path = "benchmarks/BHH_object_count/models/text_grad" 6 | adal_save_path = "benchmarks/BHH_object_count/models/adal" 7 | 8 | dspy_hotpot_qa_save_path = "benchmarks/hotpot_qa/models/dspy" 9 | text_grad_hotpot_qa_save_path = "benchmarks/hotpot_qa/models/text_grad" 10 | adal_hotpot_qa_save_path = "benchmarks/hotpot_qa/models/adal" 11 | 12 | 13 | llama3_model = { 14 | "model_client": GroqAPIClient, 15 | "model_kwargs": { 16 | "model": "llama-3.1-8b-instant", 17 | }, 18 | } 19 | gpt_3_model = { 20 | "model_client": OpenAIClient, 21 | "model_kwargs": { 22 | "model": "gpt-3.5-turbo", 23 | "max_tokens": 2000, 24 | "temperature": 0.0, 25 | "top_p": 0.99, 26 | "frequency_penalty": 0, 27 | "presence_penalty": 0, 28 | "stop": None, 29 | }, 30 | } 31 | 32 | gpt_4o_model = { 33 | "model_client": OpenAIClient, 34 | "model_kwargs": { 35 | "model": "gpt-4o", 36 | "temperature": 0.9, 37 | "top_p": 0.99, 38 | }, 39 | } 40 | 41 | 42 | def load_model(**kwargs): 43 | if "model_client" in kwargs: 44 | kwargs["model_client"] = kwargs["model_client"]() 45 | return kwargs 46 | -------------------------------------------------------------------------------- /benchmarks/hotpot_qa/__init__.py: -------------------------------------------------------------------------------- 1 | """Hotpot_QA requires a rag system where (1) llm is used to decide search query (2) retriever to retrieve the passages (3) llm to look at the passages and decide to retrieve or stop. 2 | It can also be solved with ReAct agent""" 3 | -------------------------------------------------------------------------------- /benchmarks/hotpot_qa/adal_exp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/benchmarks/hotpot_qa/adal_exp/__init__.py -------------------------------------------------------------------------------- /benchmarks/hotpot_qa/config.py: -------------------------------------------------------------------------------- 1 | dspy_save_path = "benchmarks/BHH_object_count/models/dspy" 2 | adal_save_path = "benchmarks/BHH_object_count/models/adal" 3 | 4 | from adalflow.datasets.hotpot_qa import HotPotQA 5 | 6 | 7 | def load_datasets(): 8 | 9 | trainset = HotPotQA(split="train", size=100) # 20 10 | valset = HotPotQA(split="val", size=100) # 50 11 | testset = HotPotQA(split="test", size=200) # to keep the same as the dspy #50 12 | print(f"trainset, valset: {len(trainset)}, {len(valset)}, example: {trainset[0]}") 13 | return trainset, valset, testset 14 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | source/apis/components/components* 2 | source/apis/components/_autosummary* 3 | source/apis/components/modules* 4 | source/apis/core/core* 5 | source/apis/core/modules* 6 | source/apis/eval/eval* 7 | source/apis/eval/modules* 8 | source/apis/prompts/prompts* 9 | source/apis/prompts/modules* 10 | source/apis/utils/utils* 11 | source/apis/utils/modules* 12 | source/apis/tracing/tracing* 13 | source/apis/tracing/modules* 14 | source/apis/optim/optim* 15 | source/apis/optim/modules* 16 | source/apis/datasets/datasets* 17 | tests.txt 18 | -------------------------------------------------------------------------------- /docs/CHANGLOG.md: -------------------------------------------------------------------------------- 1 | ## [0.2.7] - 2025-01-16 2 | 3 | - Added multimodal support in Generator tutorial and more explanation by Filip. 4 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | 3 | # You can set these variables from the command line. 4 | SPHINXOPTS = 5 | SPHINXBUILD = sphinx-build 6 | SPHINXPROJ = AdalFlow 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | APIDOCOUTDIR = $(SOURCEDIR)/apis 10 | PYTHON := $(shell command -v python3 2>/dev/null || command -v python 2>/dev/null) 11 | POETRY = poetry 12 | 13 | # Put it first so that "make" without argument is like "make help". 14 | help: 15 | @if command -v sphinx-binary > /dev/null 2>&1; then \ 16 | $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ; \ 17 | else \ 18 | echo "sphinx-binary is not installed. Please grab the latest version of Sphinx (via pip)." ; \ 19 | fi 20 | 21 | print_prereqs: 22 | @for tool in $(SPHINXBUILD) $(POETRY) ; do \ 23 | if command -v $${tool} > /dev/null 2>&1; then \ 24 | $${tool} --version ; \ 25 | else \ 26 | echo "$${tool} is not installed. Please grab the latest version via pip." ; \ 27 | fi \ 28 | done 29 | 30 | .PHONY: help Makefile 31 | 32 | # Catch-all target: route all unknown targets to Sphinx using the new 33 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 34 | %: Makefile 35 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 36 | 37 | apidoc: 38 | @sphinx-apidoc -o $(APIDOCOUTDIR)/core ../adalflow/adalflow/core --separate --force 39 | @sphinx-apidoc -o $(APIDOCOUTDIR)/components ../adalflow/adalflow/components --separate --force 40 | #--templatedir=$(SOURCEDIR)/_templates 41 | @sphinx-apidoc -o $(APIDOCOUTDIR)/eval ../adalflow/adalflow/eval --separate --force 42 | @sphinx-apidoc -o $(APIDOCOUTDIR)/optim ../adalflow/adalflow/optim --separate --force 43 | @sphinx-apidoc -o $(APIDOCOUTDIR)/datasets ../adalflow/adalflow/datasets --separate --force 44 | @sphinx-apidoc -o $(APIDOCOUTDIR)/utils ../adalflow/adalflow/utils --separate --force 45 | @sphinx-apidoc -o $(APIDOCOUTDIR)/tracing ../adalflow/adalflow/tracing --separate --force 46 | 47 | update_files: 48 | @echo "Inserting reference labels into RST files." 49 | @$(PYTHON) $(SOURCEDIR)/insert_labels.py 50 | @echo "Removing unnecessary strings for better formatting" 51 | @$(PYTHON) $(SOURCEDIR)/remove_string.py 52 | @echo "Removing duplicated files" 53 | @$(PYTHON) $(SOURCEDIR)/remove_files.py 54 | @echo "Renaming and updating file" 55 | @$(PYTHON) $(SOURCEDIR)/change_api_file_name.py 56 | @echo "Add autosummary of functions and classes" 57 | @$(PYTHON) $(SOURCEDIR)/insert_autosummary.py 58 | 59 | html: apidoc update_files 60 | @$(SPHINXBUILD) -b html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 61 | -------------------------------------------------------------------------------- /docs/_dummy/dummy/__init__.py: -------------------------------------------------------------------------------- 1 | """Dummy file to make this directory a package.""" 2 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "adalflow-docs" 3 | version = "0.0.0.beta.1" 4 | description = "Documentation for the adalflow project" 5 | authors = [ 6 | "Li Yin ", 7 | "Nicholas Fleischhauer ", 8 | ] 9 | license = "MIT" 10 | packages = [{ from = "_dummy", include = "dummy" }] # empty packages 11 | 12 | [tool.poetry.dependencies] 13 | python = ">=3.9, <4.0" 14 | adalflow = { path = "../adalflow", develop = true } # Follow latest adalflow version 15 | pyvis = "^0.3.2" 16 | sphinx-tabs = "^3.4.7" 17 | furo = "^2024.8.6" 18 | 19 | [tool.poetry.group.doc.dependencies] 20 | # Sphinx documentation dependencies 21 | sphinx = "^7.3.7" 22 | pydata-sphinx-theme = "^0.15.3" 23 | sphinx-design = "^0.6.0" 24 | sphinx-copybutton = "^0.5.2" 25 | nbsphinx = "^0.9.4" 26 | nbconvert = "^7.16.4" 27 | pandoc = "^2.3" 28 | readthedocs-sphinx-search = "^0.3.2" 29 | 30 | # Additional dependencies for document compilation 31 | datasets = "^2.20.0" 32 | sqlalchemy = "^2.0.31" 33 | google-generativeai = "^0.7.1" 34 | anthropic = "^0.30.1" 35 | cohere = "^5.5.8" 36 | transformers = "^4.42.3" 37 | openai = "^1.35.12" 38 | groq = "^0.9.0" 39 | pgvector = "^0.3.0" 40 | faiss-cpu = "^1.8.0.post1" 41 | ollama = "^0.3.0" 42 | qdrant-client = "^1.10.1" 43 | lancedb = "^0.14.0" 44 | diskcache = "^5.6.3" 45 | torch = "^2.4.0" 46 | 47 | # Azure client dependencies 48 | azure-identity = "^1.18.0" 49 | azure-core = "^1.31.0" 50 | 51 | [build-system] 52 | requires = ["poetry-core>=1.0.0"] 53 | build-backend = "poetry.core.masonry.api" 54 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | pydata-sphinx-theme==0.15.3 2 | sphinx-design==0.6.0 3 | sphinx-copybutton==0.5.2 4 | sphinx==7.3.7 5 | nbsphinx==0.9.4 6 | nbconvert==7.16.4 7 | PyYAML 8 | readthedocs-sphinx-search==0.3.2 9 | numpy 10 | tqdm 11 | tiktoken 12 | -------------------------------------------------------------------------------- /docs/source/_static/images/AdalFlow_task_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/AdalFlow_task_pipeline.png -------------------------------------------------------------------------------- /docs/source/_static/images/G_eval_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/G_eval_structure.png -------------------------------------------------------------------------------- /docs/source/_static/images/LLM_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/LLM_arch.png -------------------------------------------------------------------------------- /docs/source/_static/images/LightRAG-logo-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/LightRAG-logo-circle.png -------------------------------------------------------------------------------- /docs/source/_static/images/LightRAG-logo-doc.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/LightRAG-logo-doc.jpeg -------------------------------------------------------------------------------- /docs/source/_static/images/LightRAG-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/LightRAG-logo.jpg -------------------------------------------------------------------------------- /docs/source/_static/images/LightRAG_dataflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/LightRAG_dataflow.png -------------------------------------------------------------------------------- /docs/source/_static/images/RAG_Enhancements.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/RAG_Enhancements.png -------------------------------------------------------------------------------- /docs/source/_static/images/RAG_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/RAG_architecture.png -------------------------------------------------------------------------------- /docs/source/_static/images/RAG_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/RAG_workflow.png -------------------------------------------------------------------------------- /docs/source/_static/images/REALM_train_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/REALM_train_architecture.png -------------------------------------------------------------------------------- /docs/source/_static/images/ReAct.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/ReAct.jpg -------------------------------------------------------------------------------- /docs/source/_static/images/Trainable_task_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/Trainable_task_pipeline.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow-logo.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_code_samples.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_code_samples.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_debug_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_debug_report.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_files.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_issue_template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_issue_template.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_issues.png -------------------------------------------------------------------------------- /docs/source/_static/images/adalflow_rag_benchmarks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/adalflow_rag_benchmarks.png -------------------------------------------------------------------------------- /docs/source/_static/images/anthropic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/anthropic.png -------------------------------------------------------------------------------- /docs/source/_static/images/azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/azure.png -------------------------------------------------------------------------------- /docs/source/_static/images/bedrock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/bedrock.png -------------------------------------------------------------------------------- /docs/source/_static/images/classification_opt_prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/classification_opt_prompt.png -------------------------------------------------------------------------------- /docs/source/_static/images/classification_training_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/classification_training_map.png -------------------------------------------------------------------------------- /docs/source/_static/images/cohere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/cohere.png -------------------------------------------------------------------------------- /docs/source/_static/images/database.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/database.png -------------------------------------------------------------------------------- /docs/source/_static/images/dataclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/dataclass.png -------------------------------------------------------------------------------- /docs/source/_static/images/deepseek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/deepseek.png -------------------------------------------------------------------------------- /docs/source/_static/images/embedder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/embedder.png -------------------------------------------------------------------------------- /docs/source/_static/images/example_auto_grad_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/example_auto_grad_graph.png -------------------------------------------------------------------------------- /docs/source/_static/images/fireworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/fireworks.png -------------------------------------------------------------------------------- /docs/source/_static/images/generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/generator.png -------------------------------------------------------------------------------- /docs/source/_static/images/grok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/grok.png -------------------------------------------------------------------------------- /docs/source/_static/images/groq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/groq.png -------------------------------------------------------------------------------- /docs/source/_static/images/huggingface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/huggingface.png -------------------------------------------------------------------------------- /docs/source/_static/images/lance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/lance.png -------------------------------------------------------------------------------- /docs/source/_static/images/lancedb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/lancedb.png -------------------------------------------------------------------------------- /docs/source/_static/images/lightrag_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/lightrag_structure.png -------------------------------------------------------------------------------- /docs/source/_static/images/mistral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/mistral.png -------------------------------------------------------------------------------- /docs/source/_static/images/model_client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/model_client.png -------------------------------------------------------------------------------- /docs/source/_static/images/multi-providers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/multi-providers.png -------------------------------------------------------------------------------- /docs/source/_static/images/ollama.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/ollama.png -------------------------------------------------------------------------------- /docs/source/_static/images/openai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/openai.png -------------------------------------------------------------------------------- /docs/source/_static/images/pr_draft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/pr_draft.png -------------------------------------------------------------------------------- /docs/source/_static/images/qdrant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/qdrant.png -------------------------------------------------------------------------------- /docs/source/_static/images/query_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/query_1.png -------------------------------------------------------------------------------- /docs/source/_static/images/query_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/query_2.png -------------------------------------------------------------------------------- /docs/source/_static/images/replug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/replug.png -------------------------------------------------------------------------------- /docs/source/_static/images/retriever.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/retriever.png -------------------------------------------------------------------------------- /docs/source/_static/images/sambanova.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/sambanova.png -------------------------------------------------------------------------------- /docs/source/_static/images/self_rag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/self_rag.png -------------------------------------------------------------------------------- /docs/source/_static/images/tensor_parameter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/tensor_parameter.png -------------------------------------------------------------------------------- /docs/source/_static/images/together.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/together.png -------------------------------------------------------------------------------- /docs/source/_static/images/trace_graph_EvalFnToTextLoss_output_id_6ea5da3c-d414-4aae-8462-75dd1e09abab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/trace_graph_EvalFnToTextLoss_output_id_6ea5da3c-d414-4aae-8462-75dd1e09abab.png -------------------------------------------------------------------------------- /docs/source/_static/images/trace_graph_Generator_output_id_689cc5a1-6737-40a8-8faa-8bbf7bddfed8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/trace_graph_Generator_output_id_689cc5a1-6737-40a8-8faa-8bbf7bddfed8.png -------------------------------------------------------------------------------- /docs/source/_static/images/trace_graph_sum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/trace_graph_sum.png -------------------------------------------------------------------------------- /docs/source/_static/images/trace_graph_sum_id_e53cb8f9-235d-480b-b630-f480a9dfb5d0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/trace_graph_sum_id_e53cb8f9-235d-480b-b630-f480a9dfb5d0.png -------------------------------------------------------------------------------- /docs/source/_static/images/trainer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/trainer.png -------------------------------------------------------------------------------- /docs/source/_static/images/xai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/_static/images/xai.png -------------------------------------------------------------------------------- /docs/source/_templates/github-link.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /docs/source/_templates/package.rst_t: -------------------------------------------------------------------------------- 1 | {%- macro automodule(modname, options) -%} 2 | .. automodule:: {{ modname }} 3 | {%- for option in options %} 4 | :{{ option }}: 5 | {%- endfor %} 6 | {%- endmacro %} 7 | 8 | {%- macro toctree(docnames) -%} 9 | .. toctree:: 10 | :maxdepth: {{ maxdepth }} 11 | {% for docname in docnames %} 12 | {{ docname }} 13 | {%- endfor %} 14 | {%- endmacro %} 15 | 16 | {%- if is_namespace %} 17 | {{- [pkgname, "namespace"] | join(" ") | e | heading }} 18 | {% else %} 19 | {{- [pkgname, "package"] | join(" ") | e | heading }} 20 | {% endif %} 21 | 22 | {%- if is_namespace %} 23 | .. py:module:: {{ pkgname }} 24 | {% endif %} 25 | 26 | {%- if subpackages %} 27 | Subpackages 28 | ----------- 29 | 30 | {{ toctree(subpackages) }} 31 | {% endif %} 32 | 33 | {%- if submodules %} 34 | Overview 35 | ---------- 36 | 37 | .. autosummary:: 38 | :toctree: _autosummary 39 | 40 | {% for submodule in submodules if not submodule.startswith('source/apis/components/_autosummary') %} 41 | {{ submodule }} 42 | {% endfor %} 43 | {%- endif %} 44 | 45 | .. toctree:: 46 | :maxdepth: 1 47 | :hidden: 48 | 49 | {% for submodule in submodules if not submodule.startswith('source/apis/components/_autosummary') %} 50 | {{ submodule }} 51 | {% endfor %} 52 | -------------------------------------------------------------------------------- /docs/source/_templates/pydata_sphinx_theme/layout.html: -------------------------------------------------------------------------------- 1 | {# _templates/pydata_sphinx_theme/layout.html #} {% extends "!layout.html" %} {% 2 | block htmltitle %} 3 | AdalFlow: The Lightning Library for LLM Applications 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/source/apis/components/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-components: 2 | 3 | Components 4 | ============== 5 | 6 | 7 | 8 | ModelClient 9 | ~~~~~~~~~~~~~~~~~~~~ 10 | 11 | .. autosummary:: 12 | 13 | components.model_client.anthropic_client 14 | 15 | components.model_client.cohere_client 16 | 17 | components.model_client.google_client 18 | 19 | components.model_client.groq_client 20 | 21 | components.model_client.openai_client 22 | 23 | components.model_client.transformers_client 24 | 25 | components.model_client.ollama_client 26 | 27 | components.model_client.utils 28 | 29 | 30 | 31 | Retriever 32 | ~~~~~~~~~~~~~~~~~~~~ 33 | 34 | .. autosummary:: 35 | 36 | components.retriever.bm25_retriever 37 | components.retriever.faiss_retriever 38 | components.retriever.llm_retriever 39 | 40 | components.retriever.postgres_retriever 41 | 42 | components.retriever.reranker_retriever 43 | 44 | 45 | Output Parsers 46 | ~~~~~~~~~~~~~~~~~~~~ 47 | 48 | .. autosummary:: 49 | 50 | components.output_parsers.outputs 51 | components.output_parsers.dataclass_parser 52 | 53 | Agent 54 | ~~~~~~~~~~~~~~~~~~~~ 55 | 56 | .. autosummary:: 57 | 58 | components.agent.react 59 | 60 | Data Process 61 | ~~~~~~~~~~~~~~~~~~~~ 62 | 63 | .. autosummary:: 64 | 65 | 66 | components.data_process.text_splitter 67 | 68 | components.data_process.data_components 69 | 70 | Memory 71 | ~~~~~~~~~~~~~~~~~~~~ 72 | 73 | .. autosummary:: 74 | 75 | components.memory.memory 76 | 77 | Reasoning 78 | ~~~~~~~~~~~~~~~~~~~~ 79 | 80 | .. autosummary:: 81 | 82 | components.reasoning.chain_of_thought 83 | 84 | 85 | .. toctree:: 86 | :maxdepth: 1 87 | :hidden: 88 | 89 | components.model_client 90 | components.retriever 91 | components.output_parsers 92 | components.agent 93 | components.data_process 94 | components.reasoning 95 | components.memory 96 | -------------------------------------------------------------------------------- /docs/source/apis/core/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-core: 2 | 3 | Core 4 | =================== 5 | 6 | 7 | Core building blocks for RAG and more advanced functionalities, such as agents. 8 | 9 | 10 | Overview 11 | ---------- 12 | .. autosummary:: 13 | 14 | core.base_data_class 15 | core.component 16 | core.container 17 | core.default_prompt_template 18 | core.embedder 19 | core.generator 20 | core.model_client 21 | core.prompt_builder 22 | core.retriever 23 | core.string_parser 24 | core.func_tool 25 | core.tool_manager 26 | core.types 27 | core.db 28 | core.functional 29 | core.tokenizer 30 | 31 | 32 | 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | :hidden: 37 | 38 | core.base_data_class 39 | core.component 40 | core.container 41 | core.default_prompt_template 42 | core.embedder 43 | core.generator 44 | core.model_client 45 | core.prompt_builder 46 | core.retriever 47 | core.string_parser 48 | core.func_tool 49 | core.tool_manager 50 | core.types 51 | core.db 52 | core.functional 53 | core.tokenizer 54 | -------------------------------------------------------------------------------- /docs/source/apis/datasets/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-datasets: 2 | 3 | 4 | 5 | Datasets 6 | ============== 7 | 8 | Overview 9 | ---------- 10 | .. autosummary:: 11 | 12 | datasets.big_bench_hard 13 | datasets.trec 14 | datasets.hotpot_qa 15 | datasets.types 16 | 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | :hidden: 21 | 22 | datasets.big_bench_hard 23 | datasets.trec 24 | datasets.hotpot_qa 25 | datasets.types 26 | 27 | 28 | 29 | --------------- 30 | 31 | .. automodule:: datasets 32 | :members: 33 | :undoc-members: 34 | :show-inheritance: 35 | -------------------------------------------------------------------------------- /docs/source/apis/eval/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-eval: 2 | 3 | Evaluation 4 | ============== 5 | 6 | Overview 7 | ---------- 8 | .. autosummary:: 9 | 10 | 11 | eval.base 12 | 13 | eval.answer_match_acc 14 | eval.retriever_recall 15 | eval.llm_as_judge 16 | eval.g_eval 17 | 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | :hidden: 22 | 23 | eval.base 24 | eval.answer_match_acc 25 | eval.retriever_recall 26 | eval.llm_as_judge 27 | eval.g_eval 28 | 29 | 30 | 31 | --------------- 32 | 33 | .. automodule:: eval 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | -------------------------------------------------------------------------------- /docs/source/apis/optim/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-optim: 2 | 3 | Optimization 4 | ============== 5 | 6 | 7 | 8 | Base Classes and Data Structures 9 | ---------------------------------- 10 | The ``GradComponent`` and ``LossComponent`` are a subclass from ``Component`` to serve the purpose to differentiate the gradient and loss components in the optimization process. 11 | And it will be used if users want to implement their own with more customization. 12 | 13 | .. autosummary:: 14 | 15 | 16 | optim.parameter 17 | optim.optimizer 18 | optim.grad_component 19 | optim.loss_component 20 | optim.types 21 | 22 | 23 | .. optim.sampler 24 | .. optim.llm_optimizer 25 | 26 | 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | :hidden: 31 | 32 | optim.parameter 33 | optim.optimizer 34 | optim.grad_component 35 | optim.loss_component 36 | optim.types 37 | 38 | .. optim.sampler 39 | 40 | Few Shot Optimizer 41 | ---------------------------- 42 | 43 | .. autosummary:: 44 | 45 | optim.few_shot.bootstrap_optimizer 46 | 47 | .. toctree:: 48 | :maxdepth: 1 49 | :hidden: 50 | 51 | optim.few_shot 52 | 53 | Textual Gradient 54 | ---------------------------- 55 | .. autosummary:: 56 | 57 | optim.text_grad.llm_text_loss 58 | optim.text_grad.text_loss_with_eval_fn 59 | optim.text_grad.ops 60 | optim.text_grad.tgd_optimizer 61 | 62 | .. toctree:: 63 | :maxdepth: 1 64 | :hidden: 65 | 66 | optim.text_grad 67 | 68 | Trainer and AdalComponent 69 | ---------------------------- 70 | .. autosummary:: 71 | 72 | 73 | optim.trainer.adal 74 | optim.trainer.trainer 75 | 76 | .. toctree:: 77 | :maxdepth: 1 78 | :hidden: 79 | 80 | 81 | optim.adal 82 | optim.trainer 83 | 84 | 85 | Overview 86 | --------------- 87 | 88 | .. automodule:: optim 89 | :members: 90 | :undoc-members: 91 | :show-inheritance: 92 | 93 | .. make sure it follows the same order as optim.rst 94 | -------------------------------------------------------------------------------- /docs/source/apis/tracing/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-tracing: 2 | 3 | Tracing 4 | ============== 5 | 6 | Overview 7 | ---------- 8 | .. autosummary:: 9 | 10 | tracing.decorators 11 | tracing.generator_state_logger 12 | tracing.generator_call_logger 13 | 14 | 15 | .. toctree:: 16 | :maxdepth: 2 17 | :hidden: 18 | 19 | tracing.decorators 20 | tracing.generator_state_logger 21 | tracing.generator_call_logger 22 | -------------------------------------------------------------------------------- /docs/source/apis/utils/index.rst: -------------------------------------------------------------------------------- 1 | .. _apis-utils: 2 | 3 | Utils 4 | ============================= 5 | 6 | Overview 7 | ---------- 8 | .. autosummary:: 9 | 10 | utils.data 11 | utils.setup_env 12 | utils.logger 13 | utils.file_io 14 | utils.config 15 | utils.lazy_import 16 | utils.registry 17 | utils.serialization 18 | utils.cache 19 | 20 | 21 | 22 | .. toctree:: 23 | :maxdepth: 1 24 | :hidden: 25 | 26 | utils.data 27 | utils.setup_env 28 | utils.logger 29 | utils.file_io 30 | utils.config 31 | utils.lazy_import 32 | utils.registry 33 | utils.serialization 34 | utils.cache 35 | -------------------------------------------------------------------------------- /docs/source/contributor/index.rst: -------------------------------------------------------------------------------- 1 | Contributor Guide 2 | ============================= 3 | Welcome to the AdalFlow community! We're building the most user-friendly, modular, and powerful library for building and auto-optimizing LLM applications, from Chatbots and RAGs to Agents. 4 | *Think of AdalFlow for LLM applications and prompt engineering as the PyTorch/TensorFlow/JAX equivalent for AI modeling.* 5 | 6 | The goal of the library is to provide basic and fundamental building blocks to create advanced applications with auto-optimization out of the box. 7 | As we mature, we anticipate that more RAG, memory-based chatbots, or agent frameworks will be built on top of AdalFlow’s building blocks, such as `retriever` and `generator`. 8 | We highly suggest you read our :ref:`design principle` before you start contributing. 9 | 10 | We greatly appreciate all contributions, from bug fixes to new features, and value every contributor. 11 | However, we must be selective to ensure our library remains reliable for users. 12 | We hope your contributions go beyond listing your name on the repo—our goal is for you to learn, grow your skills, support your favorite projects, and give back to the community! 13 | 14 | The goal of this guide is to design the best process for maintaining the quality of our library while enabling the community to make meaningful contributions. 15 | It took us three months to set up this contributor guide, as we first tested the process with early contributors. 16 | *We are determined to make AdalFlow as great and legendary as PyTorch.* 17 | 18 | This guide covers the overall contributing process, along with development essentials for environment setup, coding, testing, and documentation. 19 | 20 | Here’s to the future of LLM applications! 21 | 22 | By `Li Yin `_. 23 | 24 | .. TODO: add a relation to the whole ecosystem 25 | 26 | 27 | 28 | .. toctree:: 29 | :caption: Contributor Guide 30 | :maxdepth: 1 31 | 32 | contribution 33 | contribute_to_code 34 | -------------------------------------------------------------------------------- /docs/source/get_started/community.rst: -------------------------------------------------------------------------------- 1 | Community 2 | ============ 3 | 4 | *Learn, share and collaborate with the AdalFlow AI community* 5 | 6 | .. You can join our community on various platforms: 7 | 8 | .. * `Discord `_ 9 | .. * `GitHub Discussion `_ 10 | 11 | .. raw:: html 12 | 13 |
14 | 15 | GitHub Repo 16 | 17 | 18 | GitHub Repo 19 | 20 | 21 | discord-invite 22 | 23 | 24 |
25 | 26 | .. .. _discord-link: 27 | 28 | .. Join our **Discord** to engage in real-time conversations with other members. 29 | 30 | .. .. _github-link: 31 | 32 | .. Participate in **GitHub Discussions** to share ideas, ask questions, and collaborate on projects. 33 | 34 | .. blogs 35 | -------------------------------------------------------------------------------- /docs/source/get_started/index.rst: -------------------------------------------------------------------------------- 1 | Get Started 2 | ============================= 3 | 4 | 5 | 6 | .. toctree:: 7 | :maxdepth: 1 8 | :caption: Get Started 9 | 10 | installation 11 | adalflow_in_15mins 12 | community 13 | -------------------------------------------------------------------------------- /docs/source/get_started/openai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/get_started/openai.jpg -------------------------------------------------------------------------------- /docs/source/insert_labels.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def add_reference_labels(directory: str): 5 | try: 6 | for filename in os.listdir(directory): 7 | if filename.endswith(".rst"): 8 | if filename == "index.rst": 9 | module_label = "-".join(directory.split("/")[-2:]) 10 | else: 11 | module_label = filename.replace(".rst", "").replace(".", "-") 12 | filepath = os.path.join(directory, filename) 13 | with open(filepath, "r+") as file: 14 | content = file.read() 15 | file.seek(0, 0) 16 | # module_label = filename.replace(".rst", "").replace(".", "-") 17 | if module_label not in content: 18 | label_line = f".. _{module_label}:\n\n" 19 | file.write(label_line + content) 20 | except Exception as e: 21 | print(f"directory {directory} not exists: {e}") 22 | 23 | 24 | if __name__ == "__main__": 25 | # Specify the directories you want to process 26 | add_reference_labels("./source/apis/core") 27 | add_reference_labels("./source/apis/components") 28 | add_reference_labels("./source/apis/datasets") 29 | 30 | add_reference_labels("./source/apis/eval") 31 | add_reference_labels("./source/apis/utils") 32 | add_reference_labels("./source/apis/tracing") 33 | add_reference_labels("./source/apis/optim") 34 | # add_reference_labels("./source/tutorials") 35 | -------------------------------------------------------------------------------- /docs/source/integrations/index.rst: -------------------------------------------------------------------------------- 1 | .. _source-integrations: 2 | 3 | Integrations 4 | =================== 5 | The integration will be listing all existing integrations and integrations we plan to add. 6 | 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :caption: Integrations 11 | 12 | integrations 13 | -------------------------------------------------------------------------------- /docs/source/new_tutorials/index.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _new_tutorials: 3 | 4 | 5 | Tutorials 6 | ============================= 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :caption: Basics 11 | :hidden: 12 | 13 | introduction 14 | prompt 15 | parser 16 | generator 17 | embedder 18 | -------------------------------------------------------------------------------- /docs/source/remove_files.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def remove_file(directory: str): 5 | """Remove duplicated files. 6 | 7 | During the automatic generation, some files are not used or duplicated, including: 8 | * modules.rst 9 | * components.rst, core.rst, prompt.rst, ... , corresponding to directory name 10 | * duplicated files in autosummary and api reference directory 11 | 12 | Args: 13 | directory (str): directory that contains duplicated files 14 | """ 15 | 16 | # remove modules.rst 17 | try: 18 | for _ in os.listdir(directory): 19 | module_file = os.path.join(directory, "modules.rst") 20 | os.remove(module_file) 21 | except Exception: 22 | print(f"No modules.rst to remove in {directory}") 23 | 24 | # remove components.rst, core.rst, prompt.rst, ... 25 | try: 26 | for _ in os.listdir(directory): 27 | name = directory.split("/")[-1] + ".rst" 28 | module_file = os.path.join(directory, name) 29 | os.remove(module_file) 30 | except Exception: 31 | print(f"No {name} to remove in {directory}") 32 | 33 | 34 | remove_file("./source/apis/components") 35 | remove_file("./source/apis/core") 36 | remove_file("./source/apis/eval") 37 | remove_file("./source/apis/datasets") 38 | remove_file("./source/apis/utils") 39 | remove_file("./source/apis/tracing") 40 | remove_file("./source/apis/optim") 41 | -------------------------------------------------------------------------------- /docs/source/remove_string.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def remove_unwanted_string(directory: str, target_string: str): 5 | """ 6 | Removes the specified string from the end of titles in .rst files within the specified directory. 7 | 8 | Parameters: 9 | - directory (str): The path to the directory containing .rst files. 10 | """ 11 | for filename in os.listdir(directory): 12 | if filename.endswith(".rst"): 13 | filepath = os.path.join(directory, filename) 14 | with open(filepath, "r+") as file: 15 | lines = file.readlines() 16 | file.seek(0) 17 | file.truncate() 18 | for line in lines: 19 | # Check if the line ends with 'module' and remove it 20 | if line.strip().endswith(target_string): 21 | line = line.replace(target_string, "") 22 | file.write(line) 23 | 24 | 25 | if __name__ == "__main__": 26 | # Specify the directory or directories you want to process 27 | directories = [ 28 | "./source/apis/core", 29 | "./source/apis/components", 30 | "./source/apis/utils", 31 | "./source/apis/datasets", 32 | "./source/apis/eval", 33 | "./source/apis/tracing", 34 | "./source/apis/optim", 35 | ] 36 | for directory in directories: 37 | remove_unwanted_string(directory, "module") 38 | remove_unwanted_string(directory, "package") 39 | remove_unwanted_string(directory, "Module contents") 40 | -------------------------------------------------------------------------------- /docs/source/tutorials/ckpt_file.rst: -------------------------------------------------------------------------------- 1 | AdalFlow JSON Viewer 2 | ============================= 3 | 4 | This is a simple viewer to display JSON data within an iframe. It helps in visualizing JSON data directly in the documentation. 5 | 6 | .. raw:: html 7 | 8 | 22 | 23 |
24 | 25 |
26 | -------------------------------------------------------------------------------- /docs/source/tutorials/class_hierarchy.rst: -------------------------------------------------------------------------------- 1 | Class Hierarchy 2 | ============================= 3 | From the plot of the `adalflow` library's class hierarchy, we can see the library is well-centered around two powerful base classes: `Component` and `DataClass`, and it maintains no more than two levels of class hierarchy. 4 | This design philosophy results in a library with bare minimum abstraction, providing developers with maximum customizability and composability. 5 | 6 | .. raw:: html 7 | 8 | 27 | 28 |
29 | 30 |
31 | -------------------------------------------------------------------------------- /docs/source/tutorials/configs.rst: -------------------------------------------------------------------------------- 1 | .. _configs: 2 | 3 | Configurations 4 | =================== 5 | -------------------------------------------------------------------------------- /docs/source/tutorials/data_class.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class TrecData: 6 | question: str 7 | label: int 8 | 9 | 10 | # adalflow 11 | -------------------------------------------------------------------------------- /docs/source/tutorials/data_pipeline.rst: -------------------------------------------------------------------------------- 1 | .. _data_pipeline: 2 | 3 | Data Pipeline 4 | ================ 5 | -------------------------------------------------------------------------------- /docs/source/tutorials/datasets.rst: -------------------------------------------------------------------------------- 1 | .. _datasets: 2 | 3 | Datasets 4 | ================ 5 | 6 | Datasets are wrapped in a :class:`Dataset` object. 7 | The `Dataset` often will be used together with :class:`utils.data.DataLoader` to load data in batches. 8 | DataLoader can also handle parallel data loading with multiple workers and apply data shuffling. 9 | 10 | To be able to use your data, you need to: 11 | 12 | 1. Create a subclass of :class:`DataClass` that defines the data structure, including a unique identifier, input and output fields for LLM calls. 13 | 14 | 2. Create a subclass of :class:`utils.data.Dataset` that defines how to load the data (local/cloud), split the data, and convert it to your defined DataClass, and how to load and preprocess the data. Optionally you can use PyTorch's dataset, the only thing is it often works with Tensor, you will need to convert it back to normal data at some point. 15 | 16 | In default, AdalFlow saved any downloaded datasets in the `~/.adalflow/cached_datasets` directory. 17 | 18 | You can see plenty of examples in the :ref:`apis-datasets` directory. 19 | The examples of `DataClass` can be found at :ref:`datasets-types`. 20 | -------------------------------------------------------------------------------- /docs/source/tutorials/few_shot_optimizer.rst: -------------------------------------------------------------------------------- 1 | Few-shot Optimizer 2 | ================== 3 | -------------------------------------------------------------------------------- /docs/source/tutorials/trace_graph.rst: -------------------------------------------------------------------------------- 1 | AdalFlow Trace Graph 2 | ============================= 3 | 4 | AdalFlow Trace Graph is able to visualize the DAG of the task pipeline and its training gradients along with the proposed value. 5 | This visualization is especially helpful for debugging. 6 | 7 | .. raw:: html 8 | 9 | 34 | 35 |
36 | 43 |
44 | -------------------------------------------------------------------------------- /docs/source/tutorials/trainer.rst: -------------------------------------------------------------------------------- 1 | .. _trainer: 2 | 3 | Trainer 4 | ================ 5 | Coming soon! 6 | 7 | Diagnose mode 8 | 9 | A pipeline can consist of multiple generators or retrievers. Each 10 | 11 | 12 | Computation graph 13 | ------------------- 14 | We design two types of graphs: 15 | 16 | 1. with a simple node-graph with consistent naming of each generator(component_name or automated name by the recursive tracing (need to be consistent eventually)) [Call it thumbnail] or a better name. 17 | 2. with details for debugging and building the pipeline. 18 | 19 | EvalFunction + Score(s) 20 | ------------------------ 21 | Currently we can assume we only support one eval_score, but eventually we need to suppport two scores, such as in the case of the multi-hop RAG. 22 | The last llm call will have one score, and the previous two generators can potentially have two scores. One is from the last score, and the second will be from the output of the multi-hop retriever. 23 | 24 | So, we need to assign a unique and global component id/name. [Score, component_id, component_name] 25 | 26 | Observability 27 | ------------------------ 28 | Building blocks include: `GeneratorCallLogger`, `RetrieverCallLogger`, `LossCallLogger` where each only traces a single component. 29 | 30 | In `AdalComponnet`, `configure_callbacks` we need both `_auto_generator_callbacks` and `_auto_retriever_callbacks` to be able to trace the call of each component. 31 | 32 | ..code-block:: python 33 | 34 | for name, generator in all_generators: 35 | call_logger = GeneratorCallLogger(save_dir=save_dir) 36 | call_logger.reset() 37 | call_logger.register_generator(name) 38 | logger_call = partial(call_logger.log_call, name) 39 | generator.register_callback( 40 | "on_complete", partial(_on_completion_callback, logger_call=logger_call) 41 | ) 42 | file_path = call_logger.get_log_location(name) 43 | file_paths.append(file_path) 44 | log.debug(f"Registered callback for {name}, file path: {file_path}") 45 | 46 | 47 | so when tracing, the `logger_metadata.json` will look like this: 48 | 49 | .. code-block:: json 50 | 51 | { 52 | "retriever.query_generators.0": "/Users/liyin/.adalflow/ckpt/MultiHopRAGAdal/diagnose_train/retriever.query_generators.0_call.jsonl", 53 | "retriever.query_generators.1": "/Users/liyin/.adalflow/ckpt/MultiHopRAGAdal/diagnose_train/retriever.query_generators.1_call.jsonl", 54 | "llm": "/Users/liyin/.adalflow/ckpt/MultiHopRAGAdal/diagnose_train/llm_call.jsonl" 55 | } 56 | 57 | TODO: 58 | - [ ] support multiple eval scores. 59 | - [ ] logger meta data 60 | 61 | { 62 | "llm": "/Users/liyin/.adalflow/ckpt/MultiHopRAGAdal/diagnose_train/llm_call.jsonl" 63 | } 64 | - [ ] retriever log: call_logger = GeneratorCallLogger(save_dir=save_dir) 65 | -------------------------------------------------------------------------------- /docs/source/use_cases/index.rst: -------------------------------------------------------------------------------- 1 | .. _use_cases: 2 | 3 | Use Cases 4 | ============================= 5 | 6 | How different parts are used to build and to auto-optimize various LLM applications. 7 | 8 | 9 | We will build use cases end-to-end, ranging from classification (classical NLP tasks) to question answering, retrieval-augmented generation (RAG), and multi-generator pipelines. 10 | 11 | .. 12 | RAG 13 | ---------------- 14 | .. list-table:: 15 | :widths: 30 70 16 | :header-rows: 1 17 | 18 | * - Part 19 | - Description 20 | * - :doc:`rag_playbook` 21 | - Comprehensive RAG playbook according to the sota research and the best practices in the industry. 22 | * - :doc:`build_a_rag` 23 | - Designing a RAG pipeline, from offline data processing to online inference. 24 | * - :doc:`eval_a_rag` 25 | - Question Answering with `bhh_hard_object_count` dataset, including textual-gradient descent and few-shot boostrap optimization. 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | :caption: RAG vibe 30 | :hidden: 31 | 32 | rag_playbook 33 | build_a_rag 34 | eval_a_rag 35 | 36 | Optimization 37 | ---------------- 38 | 39 | .. list-table:: 40 | :widths: 30 70 41 | :header-rows: 1 42 | 43 | * - Part 44 | - Description 45 | * - :doc:`question_answering` 46 | - Question Answering with `bhh_hard_object_count` dataset, including textual-gradient descent and few-shot boostrap optimization. 47 | * - :doc:`classification` 48 | - Classification with `gpt-3.5-turbo`. The optimized task pipeline performs on-par with `gpt-4o`. 49 | * - :doc:`rag_opt` 50 | - Different from previous tasks where we only used one generator component, in this of hotpotqa dataset, we will demonstrates how to optimize a pipeline composed of multiple `GradComponent`(`Retriever` & `Generator`) with a standard RAG architectures 51 | 52 | .. - RAG and multi-hop question answering with hotpotqa dataset, two generators, and one retriever, optimizing zero-shot and few-shot learning (coming soon). 53 | 54 | 55 | 56 | 57 | 58 | .. toctree:: 59 | :maxdepth: 1 60 | :caption: End-to-End 61 | :hidden: 62 | 63 | question_answering 64 | qa_computation_graph 65 | qa_text_grad_trace_graph 66 | qa_demo_trace_graph 67 | classification 68 | rag_opt 69 | -------------------------------------------------------------------------------- /docs/source/use_cases/logging.rst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/docs/source/use_cases/logging.rst -------------------------------------------------------------------------------- /docs/source/use_cases/qa_computation_graph.rst: -------------------------------------------------------------------------------- 1 | Q&A Computation Graph 2 | ============================= 3 | 4 | This demonstrates the computation graph by using the output parameter of a task pipeline with method `draw_graph`. 5 | 6 | .. raw:: html 7 | 8 | 33 | 34 |
35 | 42 |
43 | -------------------------------------------------------------------------------- /docs/source/use_cases/qa_demo_trace_graph.rst: -------------------------------------------------------------------------------- 1 | Q&A Few Shot Demo Trace Graph 2 | ============================= 3 | 4 | This demonstrates the Few-shot demostration trace graph using the `fit` method of the `Trainer` class when `debug` is set to `True`. 5 | Compared with the computation graph, this trace graph traces and the proposed new value for the demo parameters. 6 | 7 | .. raw:: html 8 | 9 | 34 |
35 | 42 |
43 | -------------------------------------------------------------------------------- /docs/source/use_cases/qa_text_grad_trace_graph.rst: -------------------------------------------------------------------------------- 1 | Q&A Text Grad Trace Graph 2 | ============================= 3 | 4 | This demonstrates the Text Grad trace graph using the `fit` method of the `Trainer` class when `debug` is set to `True`. 5 | Compared with the computation graph, this trace graph traces (1) batch-wise gradients, (2) the loss, (3) and the proposed new value for the prompt parameters. 6 | This example in particular shows a batch size of 2. 7 | 8 | .. raw:: html 9 | 10 | 35 | 36 |
37 | 44 |
45 | -------------------------------------------------------------------------------- /docs/source/use_cases/rag_end_to_end.rst: -------------------------------------------------------------------------------- 1 | RAG End to end optimization 2 | =========================== 3 | 4 | We will check a complicated scenarios on hotpotqa datasets where we have 5 | two generators, one retriever. We would optimize: 6 | * one demo parameter for each generator 7 | * one system prompt for each generator 8 | 9 | 10 | Task Pipeline 11 | -------------------------------------------------------------------------------- /notebooks/README.md: -------------------------------------------------------------------------------- 1 | This is where all of our colab notebooks will be tracked as `ipynb` files. 2 | 3 | There are still other notebooks in both `tutorials/` and `use_cases` directories that will be migrated here. 4 | 5 | ## Objective 6 | 7 | Jupyter notebooks/colabs will complement our documents at [documentation website](https://adalflow.sylph.ai) and their source code at either `tutorials/` or `use_cases/`. These are designed to be less verbose than our documents and showcase the code and results. 8 | 9 | 10 | ## Structure 11 | 12 | We provided a colab template at `notebooks/adalflow_colab_template`. You can make a copy using: 13 | 14 | `cp notebooks/adalflow_colab_template.ipynb notebooks/your_new_colab.ipynb`. 15 | 16 | The template consists of three parts: 17 | 18 | 1. Welcome to AdalFlow with library intro, outline, and installation along with environment setup. 19 | 2. Content section of your notebook. Link to Next that users can look at. 20 | 3. Issues and Feedback. 21 | 22 | # Tests 23 | 24 | ## Use kernel first if you are developing something new 25 | 26 | If you want to use an ikernel in .ipynb to test notebooks 27 | 28 | You can use the following command to install the kernel at the root of the project: 29 | 30 | ```poetry run python -m ipykernel install --user --name my-project-kernel``` 31 | 32 | ## If a new package needs to be released and tested on the changes 33 | 34 | You can go to adalflow dir and run 35 | 36 | ```bash 37 | poetry build 38 | ``` 39 | 40 | And use 41 | 42 | ```bash 43 | pip install your_path/dist/adalflow-0.1.0-py3-none-any.whl 44 | ``` 45 | 46 | to install the package. 47 | 48 | ## Link 49 | 50 | Your colab link will be: 51 | 52 | `https://colab.research.google.com/github/SylphAI-Inc/AdalFlow/blob/main/notebooks/your_new_colab.ipynb` 53 | -------------------------------------------------------------------------------- /notebooks/integration/__init__.py: -------------------------------------------------------------------------------- 1 | """To demonstrate all new model integration.""" 2 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | 2 | [tool.poetry] 3 | name = "adalflow-project" 4 | version = "0.1.0" 5 | description = "A project to develop and test the adalflow library" 6 | authors = ["Your Name "] 7 | license = "MIT" 8 | 9 | packages = [ 10 | { from = ".", include = "use_cases" }, 11 | { from = ".", include = "tutorials" }, 12 | { from = ".", include = "benchmarks" }, 13 | ] 14 | 15 | # if you cant import package, use export PYTHONPATH=$(pwd):$PYTHONPATH 16 | 17 | [tool.poetry.dependencies] 18 | python = ">=3.11, <4.0" 19 | adalflow = { path = "adalflow", develop = true } 20 | openai = "^1.34.0" 21 | black = { extras = ["jupyter"], version = "^24.10.0" } 22 | 23 | 24 | [tool.poetry.group.dev.dependencies] 25 | 26 | pre-commit = "^3.7.0" 27 | anthropic = "^0.26.0" 28 | torchmetrics = "^1.4.0.post0" 29 | jupyter = "^1.0.0" 30 | ipykernel = "^6.29.4" 31 | dataclasses-jsonschema = "^2.16.0" 32 | groq = "^0.9.0" 33 | pgvector = "^0.2.5" 34 | cohere = "^5.5.8" 35 | pydot = "^2.0.0" 36 | matplotlib = "^3.9.0" 37 | ollama = "^0.2.1" 38 | torch = ">=2.0, <3.0" 39 | textgrad = "^0.1.4" 40 | tensorboardx = "^2.6.2.2" 41 | tensorboard = "^2.17.0" 42 | dspy-ai = "^2.4.13" 43 | 44 | 45 | transformers = "^4.44.0" 46 | accelerate = "^0.33.0" 47 | faiss-cpu = "^1.8.0.post1" 48 | nltk = "^3.9.1" 49 | ragas = "^0.1.16" 50 | colorama = "^0.4.6" 51 | black = "^24.10.0" 52 | ruff = "^0.8.0" 53 | google-generativeai = "^0.8.3" 54 | together = "^1.3.14" 55 | mistralai = "1.5.0" 56 | fireworks-ai = "0.15.12" 57 | 58 | 59 | [build-system] 60 | requires = ["poetry-core>=1.0.0"] 61 | build-backend = "poetry.core.masonry.api" 62 | 63 | 64 | # for formatting and linting 65 | [tool.black] 66 | line-length = 88 67 | target-version = ["py311"] 68 | 69 | [tool.ruff] 70 | lint.extend-ignore = [ 71 | "E402", # Ignore module-level import issues 72 | "E731", 73 | "UP007", # Wants | over Union, which breaks 3.8 74 | ] 75 | line-length = 88 76 | -------------------------------------------------------------------------------- /tutorials/.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | *logs 3 | test* 4 | *.pkl 5 | .storage/ 6 | data/* 7 | traces/* 8 | developer_notes/ 9 | -------------------------------------------------------------------------------- /tutorials/__init__.py: -------------------------------------------------------------------------------- 1 | """Demonstrating how to use each component and api accross the library.""" 2 | -------------------------------------------------------------------------------- /tutorials/adalflow_dataclasses.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, field 2 | from typing import Dict 3 | import adalflow as adal 4 | from adalflow.components.model_client import GroqAPIClient 5 | 6 | # Define the QA template using jinja2 syntax 7 | qa_template = r""" 8 | You are a helpful assistant. 9 | 10 | {{output_format_str}} 11 | 12 | 13 | {{input_str}} """ 14 | 15 | 16 | # Define the output structure using dataclass 17 | @dataclass 18 | class BasicQAOutput(adal.DataClass): 19 | explanation: str = field( 20 | metadata={"desc": "A brief explanation of the concept in one sentence."} 21 | ) 22 | example: str = field(metadata={"desc": "An example of the concept in a sentence."}) 23 | __output_fields__ = ["explanation", "example"] 24 | 25 | 26 | # Define the QA component 27 | class QA(adal.Component): 28 | def __init__(self, model_client: adal.ModelClient, model_kwargs: Dict): 29 | super().__init__() 30 | parser = adal.DataClassParser(data_class=BasicQAOutput, return_data_class=True) 31 | self.generator = adal.Generator( 32 | model_client=model_client, 33 | model_kwargs=model_kwargs, 34 | template=qa_template, 35 | prompt_kwargs={"output_format_str": parser.get_output_format_str()}, 36 | output_processors=parser, 37 | ) 38 | 39 | def call(self, query: str): 40 | """Synchronous call to generate response""" 41 | return self.generator.call({"input_str": query}) 42 | 43 | async def acall(self, query: str): 44 | """Asynchronous call to generate response""" 45 | return await self.generator.acall({"input_str": query}) 46 | 47 | 48 | def run_basic_example(): 49 | """Run a basic example of the QA component""" 50 | qa = QA( 51 | model_client=GroqAPIClient(), 52 | model_kwargs={"model": "llama3-8b-8192"}, 53 | ) 54 | response = qa("What is LLM?") 55 | print("\nResponse:") 56 | print(response) 57 | print(f"BasicQAOutput: {response.data}") 58 | print(f"Explanation: {response.data.explanation}") 59 | print(f"Example: {response.data.example}") 60 | 61 | 62 | if __name__ == "__main__": 63 | from adalflow.utils import setup_env 64 | 65 | setup_env() 66 | print("Running basic QA example...") 67 | run_basic_example() 68 | -------------------------------------------------------------------------------- /tutorials/adalflow_modelclient_sync_and_async.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | from adalflow.components.model_client.openai_client import ( 4 | OpenAIClient, 5 | ) 6 | from adalflow.core.types import ModelType 7 | 8 | 9 | from adalflow.utils import setup_env 10 | 11 | 12 | def benchmark_sync_call(api_kwargs, runs=10): 13 | """ 14 | Benchmark the synchronous .call() method by running it multiple times. 15 | 16 | Parameters: 17 | - api_kwargs: The arguments to be passed to the API call 18 | - runs: The number of times to run the call (default is 10) 19 | """ 20 | responses = [] 21 | 22 | start_time = time.time() 23 | 24 | responses = [ 25 | openai_client.call( 26 | api_kwargs=api_kwargs, 27 | model_type=ModelType.LLM, 28 | ) 29 | for _ in range(runs) 30 | ] 31 | 32 | end_time = time.time() 33 | 34 | for i, response in enumerate(responses): 35 | print(f"sync call {i + 1} completed: {response}") 36 | 37 | print(f"\nSynchronous benchmark completed in {end_time - start_time:.2f} seconds") 38 | 39 | 40 | async def benchmark_async_acall(api_kwargs, runs=10): 41 | """ 42 | Benchmark the asynchronous .acall() method by running it multiple times concurrently. 43 | 44 | Parameters: 45 | - api_kwargs: The arguments to be passed to the API call 46 | - runs: The number of times to run the asynchronous call (default is 10) 47 | """ 48 | start_time = time.time() 49 | 50 | tasks = [ 51 | openai_client.acall( 52 | api_kwargs=api_kwargs, 53 | model_type=ModelType.LLM, 54 | ) 55 | for _ in range(runs) 56 | ] 57 | 58 | responses = await asyncio.gather(*tasks) 59 | 60 | end_time = time.time() 61 | 62 | for i, response in enumerate(responses): 63 | print(f"Async call {i + 1} completed: {response}") 64 | 65 | print(f"\nAsynchronous benchmark completed in {end_time - start_time:.2f} seconds") 66 | 67 | 68 | if __name__ == "__main__": 69 | setup_env() 70 | openai_client = OpenAIClient() 71 | 72 | prompt = "Tell me a joke." 73 | 74 | model_kwargs = {"model": "gpt-3.5-turbo", "temperature": 0.5, "max_tokens": 100} 75 | api_kwargs = openai_client.convert_inputs_to_api_kwargs( 76 | input=prompt, model_kwargs=model_kwargs, model_type=ModelType.LLM 77 | ) 78 | 79 | print("Starting synchronous benchmark...\n") 80 | benchmark_sync_call(api_kwargs) 81 | 82 | print("\nStarting asynchronous benchmark...\n") 83 | asyncio.run(benchmark_async_acall(api_kwargs)) 84 | -------------------------------------------------------------------------------- /tutorials/adalflow_text_splitter.py: -------------------------------------------------------------------------------- 1 | "Code for tutorial: https://adalflow.sylph.ai/tutorials/text_splitter.html" 2 | 3 | from adalflow.components.data_process.text_splitter import TextSplitter 4 | from adalflow.core.types import Document 5 | from typing import Optional, Dict 6 | 7 | 8 | def split_by_words( 9 | text: str, chunk_size: int = 5, chunk_overlap: int = 1, doc_id: Optional[str] = None 10 | ) -> list: 11 | 12 | text_splitter = TextSplitter( 13 | split_by="word", chunk_size=chunk_size, chunk_overlap=chunk_overlap 14 | ) 15 | 16 | doc = Document(text=text, id=doc_id or "doc1") 17 | 18 | return text_splitter.call(documents=[doc]) 19 | 20 | 21 | def split_by_tokens( 22 | text: str, chunk_size: int = 5, chunk_overlap: int = 0, doc_id: Optional[str] = None 23 | ) -> list: 24 | 25 | text_splitter = TextSplitter( 26 | split_by="token", chunk_size=chunk_size, chunk_overlap=chunk_overlap 27 | ) 28 | 29 | doc = Document(text=text, id=doc_id or "doc1") 30 | 31 | return text_splitter.call(documents=[doc]) 32 | 33 | 34 | def split_by_custom( 35 | text: str, 36 | split_by: str, 37 | separators: Dict[str, str], 38 | chunk_size: int = 1, 39 | chunk_overlap: int = 0, 40 | doc_id: Optional[str] = None, 41 | ) -> list: 42 | 43 | text_splitter = TextSplitter( 44 | split_by=split_by, 45 | chunk_size=chunk_size, 46 | chunk_overlap=chunk_overlap, 47 | separators=separators, 48 | ) 49 | 50 | doc = Document(text=text, id=doc_id or "doc1") 51 | 52 | return text_splitter.call(documents=[doc]) 53 | 54 | 55 | def example_usage(): 56 | text = "Example text. More example text. Even more text to illustrate." 57 | word_splits = split_by_words(text, chunk_size=5, chunk_overlap=1) 58 | print("\nWord Split Example:") 59 | for doc in word_splits: 60 | print(doc) 61 | 62 | token_splits = split_by_tokens(text, chunk_size=5, chunk_overlap=0) 63 | print("\nToken Split Example:") 64 | for doc in token_splits: 65 | print(doc) 66 | 67 | question_text = "What is your name? How old are you? Where do you live?" 68 | custom_splits = split_by_custom( 69 | text=question_text, 70 | split_by="question", 71 | chunk_size=1, 72 | separators={"question": "?"}, 73 | ) 74 | print("\nCustom Separator Example:") 75 | for doc in custom_splits: 76 | print(doc) 77 | 78 | 79 | if __name__ == "__main__": 80 | example_usage() 81 | -------------------------------------------------------------------------------- /tutorials/adalflow_tracing.py: -------------------------------------------------------------------------------- 1 | """ 2 | This script demonstrates the usage of AdalFlow's tracing functionality. 3 | It shows how to track Generator states and changes during development. 4 | """ 5 | 6 | from adalflow.tracing import trace_generator_states 7 | from adalflow.core import Generator 8 | import adalflow as adal 9 | from adalflow.components.model_client import OpenAIClient 10 | 11 | 12 | template_doc = r""" You are a doctor User: {{input_str}}""" 13 | 14 | 15 | @trace_generator_states() 16 | class DocQA(adal.Component): 17 | 18 | def __init__(self): 19 | super(DocQA, self).__init__() 20 | self.generator = Generator( 21 | template=template_doc, 22 | model_client=OpenAIClient(), 23 | model_kwargs={"model": "gpt-4-turbo-preview"}, 24 | ) 25 | 26 | def call(self, query: str) -> str: 27 | 28 | return self.generator(prompt_kwargs={"input_str": query}).data 29 | 30 | 31 | def main(): 32 | 33 | doc_qa = DocQA() 34 | 35 | queries = [ 36 | "What are the common symptoms of the flu?", 37 | "How can I manage my allergies?", 38 | "What should I do for a minor burn?", 39 | ] 40 | 41 | for query in queries: 42 | print(f"\nQuery: {query}") 43 | response = doc_qa.call(query) 44 | print(f"Response: {response}") 45 | 46 | print("\nNote: Generator states have been logged to the traces directory.") 47 | print("You can find the logs in: ./traces/DocQA/generator_state_trace.json") 48 | 49 | 50 | if __name__ == "__main__": 51 | from adalflow.utils import setup_env 52 | 53 | setup_env() 54 | main() 55 | -------------------------------------------------------------------------------- /tutorials/component.py: -------------------------------------------------------------------------------- 1 | """Code for tutorial: https://adalflow.sylph.ai/tutorials/component.html""" 2 | 3 | from adalflow.core import Component, Generator 4 | from adalflow.components.model_client import OpenAIClient 5 | 6 | 7 | class EnhanceQuery(Component): 8 | def __init__(self): 9 | super().__init__() 10 | 11 | def call(self, query: str) -> str: 12 | return query + "Please be concise and only list the top treatments." 13 | 14 | 15 | template_doc = r""" You are a doctor 16 | {{input_str}} """ 17 | 18 | 19 | class DocQA(Component): 20 | def __init__(self): 21 | super().__init__() 22 | self.doc = Generator( 23 | template=template_doc, 24 | model_client=OpenAIClient(), 25 | model_kwargs={"model": "gpt-3.5-turbo"}, 26 | ) 27 | 28 | def call(self, query: str) -> str: 29 | return self.doc(prompt_kwargs={"input_str": query}).data 30 | 31 | 32 | if __name__ == "__main__": 33 | from adalflow.utils import setup_env 34 | 35 | setup_env() 36 | doc = DocQA() 37 | states = doc.to_dict() 38 | # print(states) 39 | # print(doc.__dict__) 40 | 41 | doc2 = DocQA.from_dict(states) 42 | # print(doc2.__dict__) 43 | # print(doc2.to_dict()) 44 | print(doc2) 45 | 46 | # to_dict and from_dict should be the same 47 | assert doc2.to_dict() == doc.to_dict(), "to_dict and from_dict should be the same" 48 | 49 | print(doc("What is the best treatment for headache?")) 50 | print(doc2("What is the best treatment for headache?")) 51 | 52 | # # list other subcomponents 53 | # for subcomponent in doc.named_components(): 54 | # print(subcomponent) 55 | 56 | # doc.register_parameter("demo", param=Parameter(data="demo")) 57 | 58 | # # list all parameters 59 | # for param in doc.named_parameters(): 60 | # print(param) 61 | 62 | # print(doc.to_dict()) 63 | 64 | # from adalflow.utils.file_io import save_json 65 | 66 | # save_json(doc.to_dict(), "doc.json") 67 | 68 | # print(doc.state_dict()) 69 | # print(doc.call("What is the best treatment for a cold?")) 70 | 71 | # enhance_query = EnhanceQuery() 72 | 73 | # seq = Sequential(enhance_query, doc) 74 | # query = "What is the best treatment for headache?" 75 | # print(seq(query)) 76 | # print(seq) 77 | -------------------------------------------------------------------------------- /tutorials/deepseek_note.py: -------------------------------------------------------------------------------- 1 | from adalflow.components.model_client import DeepSeekClient 2 | from adalflow.core.types import ModelType 3 | 4 | from adalflow.utils import setup_env 5 | 6 | # Initialize the DeepSeekClient 7 | setup_env() 8 | deepseek_client = DeepSeekClient() 9 | 10 | # Example query for the DeepSeek reasoning model 11 | query = "What is the capital of France?" 12 | 13 | # === Example 1: Using DeepSeek LLM Model === 14 | print("=== Example 1: Using DeepSeek LLM Model ===") 15 | 16 | # Set the model type for LLM 17 | model_type = ModelType.LLM 18 | 19 | # Define the system prompt and user query 20 | system_prompt = "You are a helpful assistant." 21 | prompt = f"\n{system_prompt}\n\n\n{query}\n" 22 | 23 | # Define model-specific parameters 24 | model_kwargs = { 25 | "model": "deepseek-reasoner", 26 | "temperature": 0.7, 27 | "max_tokens": 100, 28 | "stream": False, 29 | } 30 | 31 | # Convert the inputs into API-compatible arguments 32 | api_kwargs = deepseek_client.convert_inputs_to_api_kwargs( 33 | input=prompt, model_kwargs=model_kwargs, model_type=model_type 34 | ) 35 | print(f"api_kwargs: {api_kwargs}") 36 | 37 | # Call the DeepSeek reasoning model 38 | response = deepseek_client.call(api_kwargs=api_kwargs, model_type=model_type) 39 | 40 | # Parse the response 41 | response_text = deepseek_client.parse_chat_completion(response) 42 | print(f"response_text: {response_text}") 43 | 44 | # === Example 2: Using DeepSeek Embedder Model === 45 | print("\n=== Example 2: Using DeepSeek Embedder Model ===") 46 | 47 | # Set the model type for embedding 48 | model_type = ModelType.EMBEDDER 49 | 50 | # Define the input for embedding 51 | input = [query] * 2 # Batch embedding 52 | 53 | # Define model-specific parameters for embedding 54 | model_kwargs = { 55 | "model": "deepseek-embedder", # Replace with the actual embedding model name from DeepSeek 56 | "dimensions": 512, # Example dimension size 57 | "encoding_format": "float", 58 | } 59 | 60 | # Convert the inputs into API-compatible arguments 61 | api_kwargs = deepseek_client.convert_inputs_to_api_kwargs( 62 | input=input, model_kwargs=model_kwargs, model_type=model_type 63 | ) 64 | print(f"api_kwargs: {api_kwargs}") 65 | 66 | # Call the DeepSeek embedding model 67 | response = deepseek_client.call(api_kwargs=api_kwargs, model_type=model_type) 68 | 69 | # Parse the embedding response 70 | response_embedder_output = deepseek_client.parse_embedding_response(response) 71 | print(f"response_embedder_output: {response_embedder_output}") 72 | -------------------------------------------------------------------------------- /tutorials/default_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator": { 3 | "model_client": { 4 | "component_name": "OpenAIClient", 5 | "component_config": {} 6 | }, 7 | "model_kwargs": {"model": "gpt-3.5-turbo", "temperature": 0} 8 | }, 9 | "embedder_openai": { 10 | "model_client": { 11 | "component_name": "OpenAIClient", 12 | "component_config": {} 13 | }, 14 | "model_kwargs": { 15 | "model": "text-embedding-3-small", 16 | "dimensions": 256, 17 | "encoding_format": "float" 18 | } 19 | }, 20 | "document_splitter": { 21 | "component_name": "DocumentSplitter", 22 | "component_config": { 23 | "split_by": "word", 24 | "split_length": 400, 25 | "split_overlap": 200 26 | } 27 | }, 28 | "to_embeddings": { 29 | "component_name": "ToEmbeddings", 30 | "component_config": { 31 | "embedder": { 32 | "component_name": "Embedder", 33 | "component_config": { 34 | "model_client": { 35 | "component_name": "OpenAIClient", 36 | "component_config": {} 37 | }, 38 | "model_kwargs": { 39 | "model": "text-embedding-3-small", 40 | "dimensions": 256, 41 | "encoding_format": "float" 42 | } 43 | } 44 | }, 45 | "batch_size": 100 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tutorials/evaluation/eval_retriever.py: -------------------------------------------------------------------------------- 1 | from adalflow.eval import RetrieverRecall 2 | 3 | retrieved_contexts = [ 4 | "Apple is founded before Google.", 5 | "Feburary has 28 days in common years. Feburary has 29 days in leap years. Feburary is the second month of the year.", 6 | ] 7 | gt_contexts = [ 8 | [ 9 | "Apple is founded in 1976.", 10 | "Google is founded in 1998.", 11 | "Apple is founded before Google.", 12 | ], 13 | ["Feburary has 28 days in common years", "Feburary has 29 days in leap years"], 14 | ] 15 | 16 | 17 | def evaluate_retriever(retrieved_contexts, gt_contexts): 18 | retriever_recall = RetrieverRecall() 19 | avg_recall, recall_list = retriever_recall.compute(retrieved_contexts, gt_contexts) 20 | return avg_recall, recall_list 21 | 22 | 23 | if __name__ == "__main__": 24 | avg_recall, recall_list = evaluate_retriever(retrieved_contexts, gt_contexts) 25 | print(f"avg_recall: {avg_recall}, recall_list: {recall_list}") 26 | -------------------------------------------------------------------------------- /tutorials/generator_all_providers.py: -------------------------------------------------------------------------------- 1 | # This doc shows how to use all different providers in the Generator class. 2 | 3 | import adalflow as adal 4 | 5 | 6 | def use_all_providers(): 7 | openai_llm = adal.Generator( 8 | model_client=adal.OpenAIClient(), 9 | model_kwargs={"model": "gpt-3.5-turbo"}, 10 | ) 11 | groq_llm = adal.Generator( 12 | model_client=adal.GroqAPIClient(), 13 | model_kwargs={"model": "llama3-8b-8192"}, 14 | ) 15 | anthropic_llm = adal.Generator( 16 | model_client=adal.AnthropicAPIClient(), 17 | model_kwargs={"model": "claude-3-5-sonnet-20241022"}, 18 | ) 19 | google_gen_ai_llm = adal.Generator( 20 | model_client=adal.GoogleGenAIClient(), 21 | model_kwargs={"model": "gemini-1.0-pro"}, 22 | ) 23 | ollama_llm = adal.Generator( 24 | model_client=adal.OllamaClient(), 25 | model_kwargs={"model": "llama3.2:1b"}, 26 | ) 27 | # need to run ollama pull llama3.2:1b first to use this model 28 | 29 | # aws_bedrock_llm = adal.Generator( 30 | # model_client=adal.BedrockAPIClient(), 31 | # model_kwargs={"modelId": "amazon.mistral.instruct-7b"}, 32 | # ) 33 | 34 | prompt_kwargs = {"input_str": "What is the meaning of life in one sentence?"} 35 | 36 | openai_response = openai_llm(prompt_kwargs) 37 | groq_response = groq_llm(prompt_kwargs) 38 | anthropic_response = anthropic_llm(prompt_kwargs) 39 | google_gen_ai_response = google_gen_ai_llm(prompt_kwargs) 40 | ollama_response = ollama_llm(prompt_kwargs) 41 | # aws_bedrock_llm_response = aws_bedrock_llm(prompt_kwargs) 42 | 43 | print(f"OpenAI: {openai_response}\n") 44 | print(f"Groq: {groq_response}\n") 45 | print(f"Anthropic: {anthropic_response}\n") 46 | print(f"Google GenAI: {google_gen_ai_response}\n") 47 | print(f"Ollama: {ollama_response}\n") 48 | # print(f"AWS Bedrock: {aws_bedrock_llm_response}\n") 49 | 50 | 51 | if __name__ == "__main__": 52 | adal.setup_env() 53 | use_all_providers() 54 | -------------------------------------------------------------------------------- /tutorials/ollama_client_simple_qa.py: -------------------------------------------------------------------------------- 1 | from adalflow.core.generator import Generator 2 | from adalflow.core.component import Component 3 | from adalflow.core.embedder import Embedder 4 | from adalflow.components.model_client.ollama_client import OllamaClient 5 | from adalflow.utils import setup_env 6 | 7 | from ollama import Client 8 | 9 | setup_env() 10 | 11 | client = Client(host="http://localhost:11434") 12 | # response = client.chat( 13 | # model="llama3", 14 | # messages=[ 15 | # { 16 | # "role": "user", 17 | # "content": "Why is the sky blue?", 18 | # }, 19 | # ], 20 | # ) 21 | # print(response) 22 | 23 | response = client.generate( 24 | model="llama3", 25 | prompt="Why is the sky blue?", 26 | ) 27 | # print(response) 28 | 29 | # kwargs = { 30 | # "model": "jina/jina-embeddings-v2-base-en:latest", 31 | # } 32 | 33 | # response = client.embeddings( 34 | # model="jina/jina-embeddings-v2-base-en:latest", 35 | # prompt="Welcome", 36 | # ) 37 | # print(response) 38 | 39 | 40 | # Create components that will serve as function calls to our local LLM 41 | class SimpleQA(Component): 42 | def __init__(self): 43 | super().__init__() 44 | model_kwargs = {"model": "internlm2"} 45 | self.generator = Generator( 46 | model_client=OllamaClient(), 47 | model_kwargs=model_kwargs, 48 | ) 49 | 50 | def call(self, input: dict) -> str: 51 | return self.generator.call({"input_str": str(input)}) 52 | 53 | async def acall(self, input: dict) -> str: 54 | return await self.generator.acall({"input_str": str(input)}) 55 | 56 | 57 | def prepare_embedder(): 58 | # ollama pull jina/jina-embeddings-v2-base-en:latest 59 | embedder = Embedder( 60 | model_client=OllamaClient(), 61 | model_kwargs={"model": "jina/jina-embeddings-v2-base-en:latest"}, 62 | ) 63 | return embedder 64 | 65 | 66 | def test_embedder(): 67 | embedder = prepare_embedder() 68 | response = embedder.call(input="Hello world") 69 | print(response) 70 | 71 | 72 | async def test_async_embedder(): 73 | embedder = prepare_embedder() 74 | response = await embedder.acall(input="Hello world") 75 | print(response) 76 | return response 77 | 78 | 79 | if __name__ == "__main__": 80 | import asyncio 81 | 82 | test_embedder() 83 | asyncio.run(test_async_embedder()) 84 | qa = SimpleQA() 85 | print(qa("What is the capital of France?")) 86 | -------------------------------------------------------------------------------- /tutorials/postgres.sql: -------------------------------------------------------------------------------- 1 | -- CREATE EXTENSION vector; 2 | -- list table with sql 3 | select * 4 | from data_paul_graham_essay; 5 | select * 6 | from document; 7 | -- drop table document; 8 | -------------------------------------------------------------------------------- /tutorials/prompt_note.py: -------------------------------------------------------------------------------- 1 | def python_str_format_example(task_desc_str: str, input_str: str): 2 | 3 | # percent(%) formatting 4 | print("%s User: %s" % (task_desc_str, input_str)) 5 | 6 | # format() method with kwargs 7 | print( 8 | "{task_desc_str} User: {input_str}".format( 9 | task_desc_str=task_desc_str, input_str=input_str 10 | ) 11 | ) 12 | 13 | # f-string 14 | print(f"{task_desc_str} User: {input_str}") 15 | 16 | # Templates 17 | from string import Template 18 | 19 | t = Template("$task_desc_str User: $input_str") 20 | print(t.substitute(task_desc_str=task_desc_str, input_str=input_str)) 21 | 22 | 23 | def jinja2_template_example(template, **kwargs): 24 | from jinja2 import Template 25 | 26 | t = Template(template, trim_blocks=True, lstrip_blocks=True) 27 | print(t.render(**kwargs)) 28 | 29 | 30 | def adalflow_prompt(template, task_desc_str, input_str, tools=None): 31 | from adalflow.core.prompt_builder import Prompt 32 | 33 | prompt = Prompt( 34 | template=template, 35 | prompt_kwargs={ 36 | "task_desc_str": task_desc_str, 37 | "tools": tools, 38 | }, 39 | ) 40 | print(prompt) 41 | print(prompt(input_str=input_str)) 42 | 43 | saved_prompt = prompt.to_dict() 44 | restored_prompt = Prompt.from_dict(saved_prompt) 45 | print( 46 | restored_prompt == prompt 47 | ) # False as the jinja2 template can not be serialized, but we recreated the template from the string at the time of restoration, so it works the same 48 | print(restored_prompt) 49 | 50 | 51 | def adalflow_default_prompt(): 52 | from adalflow.core.prompt_builder import Prompt 53 | 54 | prompt = Prompt() 55 | input_str = "What is the capital of France?" 56 | output = prompt(input_str=input_str) 57 | print(output) 58 | 59 | 60 | if __name__ == "__main__": 61 | 62 | task_desc_str = "You are a helpful assitant" 63 | input_str = "What is the capital of France?" 64 | tools = ["google", "wikipedia", "wikidata"] 65 | template = r"""{{ task_desc_str }} 66 | {# tools #} 67 | {% if tools %} 68 | 69 | {% for tool in tools %} 70 | {{loop.index}}. {{ tool }} 71 | {% endfor %} 72 | 73 | {% endif %} 74 | User: {{ input_str }}""" 75 | python_str_format_example(task_desc_str, input_str) 76 | jinja2_template_example(template, task_desc_str=task_desc_str, input_str=input_str) 77 | jinja2_template_example( 78 | template, task_desc_str=task_desc_str, input_str=input_str, tools=tools 79 | ) 80 | adalflow_prompt( 81 | template, task_desc_str=task_desc_str, input_str=input_str, tools=tools 82 | ) 83 | 84 | adalflow_default_prompt() 85 | -------------------------------------------------------------------------------- /tutorials/rag.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "We have already seen how the RAG is implemented in data.\n", 8 | "In this note, we will focus more on how to make each component more configurable, \n", 9 | "espeically the data processing pipeline to help us with experiments where we will see how useful they are in benchmarking." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "# the data pipeline and the backend data processing\n", 19 | "from adalflow.core.embedder import Embedder\n", 20 | "from adalflow.core.types import ModelClientType\n", 21 | "from adalflow.components.data_process import TextSplitter, ToEmbeddings\n", 22 | "from adalflow.core.container import Sequential\n", 23 | "\n", 24 | "\n", 25 | "def prepare_data_pipeline():\n", 26 | " model_kwargs = {\n", 27 | " \"model\": \"text-embedding-3-small\",\n", 28 | " \"dimensions\": 256,\n", 29 | " \"encoding_format\": \"float\",\n", 30 | " }\n", 31 | "\n", 32 | " splitter_config = {\"split_by\": \"word\", \"split_length\": 50, \"split_overlap\": 10}\n", 33 | "\n", 34 | " splitter = TextSplitter(**splitter_config)\n", 35 | " embedder = Embedder(\n", 36 | " model_client=ModelClientType.OPENAI(), model_kwargs=model_kwargs\n", 37 | " )\n", 38 | " embedder_transformer = ToEmbeddings(embedder, batch_size=2)\n", 39 | " data_transformer = Sequential(splitter, embedder_transformer)\n", 40 | " print(data_transformer)" 41 | ] 42 | } 43 | ], 44 | "metadata": { 45 | "kernelspec": { 46 | "display_name": "lightrag-project", 47 | "language": "python", 48 | "name": "light-rag-project" 49 | }, 50 | "language_info": { 51 | "codemirror_mode": { 52 | "name": "ipython", 53 | "version": 3 54 | }, 55 | "file_extension": ".py", 56 | "mimetype": "text/x-python", 57 | "name": "python", 58 | "nbconvert_exporter": "python", 59 | "pygments_lexer": "ipython3", 60 | "version": "3.11.6" 61 | } 62 | }, 63 | "nbformat": 4, 64 | "nbformat_minor": 2 65 | } 66 | -------------------------------------------------------------------------------- /tutorials/rag/config.py: -------------------------------------------------------------------------------- 1 | configs = { 2 | "embedder": { 3 | "batch_size": 100, 4 | "model_kwargs": { 5 | "model": "text-embedding-3-small", 6 | "dimensions": 256, 7 | "encoding_format": "float", 8 | }, 9 | }, 10 | "retriever": { 11 | "top_k": 2, 12 | }, 13 | "generator": { 14 | "model": "gpt-3.5-turbo", 15 | "temperature": 0.3, 16 | "stream": False, 17 | }, 18 | "text_splitter": { 19 | "split_by": "word", 20 | "chunk_size": 400, 21 | "chunk_overlap": 200, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /tutorials/retriever/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/tutorials/retriever/__init__.py -------------------------------------------------------------------------------- /tutorials/retriever/adalflow_lancedb.py: -------------------------------------------------------------------------------- 1 | from adalflow.components.retriever.lancedb_retriver import LanceDBRetriever 2 | 3 | from adalflow.core.embedder import Embedder 4 | from adalflow.core.types import ModelClientType 5 | 6 | model_kwargs = { 7 | "model": "text-embedding-3-small", 8 | "dimensions": 256, 9 | "encoding_format": "float", 10 | } 11 | 12 | documents = [ 13 | { 14 | "title": "The Impact of Renewable Energy on the Economy", 15 | "content": "Renewable energy technologies not only help in reducing greenhouse gas emissions but also contribute significantly to the economy by creating jobs.", 16 | }, 17 | { 18 | "title": "Understanding Solar Panels", 19 | "content": "Solar panels convert sunlight into electricity by allowing photons, or light particles, to knock electrons free from atoms.", 20 | }, 21 | { 22 | "title": "Pros and Cons of Solar Energy", 23 | "content": "While solar energy offers substantial environmental benefits, such as reducing carbon footprints and pollution, it also has downsides.", 24 | }, 25 | { 26 | "title": "Renewable Energy and Its Effects", 27 | "content": "Renewable energy sources like wind, solar, and hydro power play a crucial role in combating climate change.", 28 | }, 29 | ] 30 | 31 | 32 | def init_retriever(): 33 | embedder = Embedder( 34 | model_client=ModelClientType.OPENAI(), model_kwargs=model_kwargs 35 | ) 36 | retriever = LanceDBRetriever( 37 | embedder=embedder, dimensions=256, db_uri="/tmp/lancedb", top_k=2 38 | ) 39 | retriever.add_documents(documents) 40 | return retriever 41 | 42 | 43 | if __name__ == "__main__": 44 | from adalflow.utils import setup_env 45 | 46 | setup_env() 47 | 48 | retriever = init_retriever() 49 | output = retriever.retrieve(query="What are the benefits of renewable energy?") 50 | print(output) 51 | -------------------------------------------------------------------------------- /tutorials/retriever/data.py: -------------------------------------------------------------------------------- 1 | query_1 = "What are the benefits of renewable energy?" # gt is [0, 3] 2 | query_2 = "How do solar panels impact the environment?" # gt is [1, 2] 3 | 4 | documents = [ 5 | { 6 | "title": "The Impact of Renewable Energy on the Economy", 7 | "content": "Renewable energy technologies not only help in reducing greenhouse gas emissions but also contribute significantly to the economy by creating jobs in the manufacturing and installation sectors. The growth in renewable energy usage boosts local economies through increased investment in technology and infrastructure.", 8 | }, 9 | { 10 | "title": "Understanding Solar Panels", 11 | "content": "Solar panels convert sunlight into electricity by allowing photons, or light particles, to knock electrons free from atoms, generating a flow of electricity. Solar panels are a type of renewable energy technology that has been found to have a significant positive effect on the environment by reducing the reliance on fossil fuels.", 12 | }, 13 | { 14 | "title": "Pros and Cons of Solar Energy", 15 | "content": "While solar energy offers substantial environmental benefits, such as reducing carbon footprints and pollution, it also has downsides. The production of solar panels can lead to hazardous waste, and large solar farms require significant land, which can disrupt local ecosystems.", 16 | }, 17 | { 18 | "title": "Renewable Energy and Its Effects", 19 | "content": "Renewable energy sources like wind, solar, and hydro power play a crucial role in combating climate change. They do not produce greenhouse gases during operation, making them essential for sustainable development. However, the initial setup and material sourcing for these technologies can still have environmental impacts.", 20 | }, 21 | ] 22 | -------------------------------------------------------------------------------- /tutorials/retriever/local_db.py: -------------------------------------------------------------------------------- 1 | # show case the get_items and get_transformed_data methods 2 | -------------------------------------------------------------------------------- /use_cases/.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | ../index.faiss 3 | /extend 4 | -------------------------------------------------------------------------------- /use_cases/README.md: -------------------------------------------------------------------------------- 1 | TODO List: 2 | 3 | 1. Align LLM judge using annoated generated text - ground truth text pairs. 4 | -------------------------------------------------------------------------------- /use_cases/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/__init__.py -------------------------------------------------------------------------------- /use_cases/classification/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/classification/__init__.py -------------------------------------------------------------------------------- /use_cases/classification/data.py: -------------------------------------------------------------------------------- 1 | from adalflow.datasets.trec import TrecDataset 2 | from adalflow.datasets.types import TrecData 3 | from dataclasses import dataclass, field 4 | 5 | _COARSE_LABELS = [ 6 | "ABBR", 7 | "ENTY", 8 | "DESC", 9 | "HUM", 10 | "LOC", 11 | "NUM", 12 | ] 13 | 14 | 15 | @dataclass 16 | class TRECExtendedData(TrecData): 17 | """Dataclass for TREC dataset""" 18 | 19 | rationale: str = field( 20 | metadata={ 21 | "desc": "Your step-by-step reasoning to classify the question to class_name" 22 | }, 23 | default=None, 24 | ) 25 | 26 | __input_fields__ = ["question"] 27 | __output_fields__ = ["rationale", "class_name"] 28 | 29 | 30 | def load_datasets(): 31 | """Load the dataset""" 32 | train_data = TrecDataset(split="train") 33 | val_data = TrecDataset(split="val") 34 | test_data = TrecDataset(split="test") 35 | return train_data, val_data, test_data # 0.694, 0.847 36 | -------------------------------------------------------------------------------- /use_cases/configs/rag.yaml: -------------------------------------------------------------------------------- 1 | vectorizer: 2 | batch_size: 100 3 | model_kwargs: 4 | model: text-embedding-3-small 5 | dimensions: 256 6 | encoding_format: float 7 | 8 | retriever: 9 | top_k: 2 10 | 11 | generator: 12 | model: gpt-3.5-turbo 13 | temperature: 0.3 14 | stream: false 15 | 16 | text_splitter: 17 | split_by: word 18 | chunk_size: 400 19 | chunk_overlap: 200 20 | -------------------------------------------------------------------------------- /use_cases/configs/rag_hotpotqa.yaml: -------------------------------------------------------------------------------- 1 | vectorizer: 2 | batch_size: 100 3 | model_kwargs: 4 | model: text-embedding-3-small 5 | dimensions: 256 6 | encoding_format: float 7 | 8 | retriever: 9 | top_k: 2 10 | 11 | generator: 12 | model: gpt-3.5-turbo 13 | temperature: 0.3 14 | stream: false 15 | 16 | text_splitter: 17 | split_by: sentence 18 | chunk_size: 1 19 | chunk_overlap: 0 20 | 21 | llm_evaluator: 22 | model: gpt-3.5-turbo 23 | temperature: 0.3 24 | stream: false 25 | -------------------------------------------------------------------------------- /use_cases/question_answering/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/question_answering/__init__.py -------------------------------------------------------------------------------- /use_cases/question_answering/bbh/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/question_answering/bbh/__init__.py -------------------------------------------------------------------------------- /use_cases/question_answering/bbh/object_count/__init__.py: -------------------------------------------------------------------------------- 1 | from adalflow.utils import setup_env 2 | 3 | setup_env() 4 | -------------------------------------------------------------------------------- /use_cases/question_answering/bbh/object_count/diagnose.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | import adalflow as adal 3 | from use_cases.question_answering.bbh.object_count.task import ObjectCountTaskPipeline 4 | 5 | from adalflow.datasets.types import Example 6 | from adalflow.eval.answer_match_acc import AnswerMatchAcc 7 | 8 | 9 | class ObjectCountAdalComponent(adal.AdalComponent): 10 | def __init__(self, model_client: adal.ModelClient, model_kwargs: Dict): 11 | task = ObjectCountTaskPipeline(model_client, model_kwargs) 12 | eval_fn = AnswerMatchAcc(type="exact_match").compute_single_item 13 | super().__init__(task=task, eval_fn=eval_fn) 14 | 15 | def prepare_task(self, sample: Example): 16 | return self.task.call, {"question": sample.question, "id": sample.id} 17 | 18 | def prepare_eval(self, sample: Example, y_pred: adal.GeneratorOutput) -> float: 19 | y_label = -1 20 | if ( 21 | y_pred is not None and y_pred.data is not None 22 | ): # if y_pred and y_pred.data: might introduce bug when the data is 0 23 | y_label = y_pred.data 24 | return self.eval_fn, {"y": y_label, "y_gt": sample.answer} 25 | 26 | 27 | def diagnose( 28 | model_client: adal.ModelClient, 29 | model_kwargs: Dict, 30 | ) -> Dict: 31 | from use_cases.question_answering.bbh.data import load_datasets 32 | 33 | trainset, valset, testset = load_datasets() 34 | # use max_samples=10 to test the code 35 | 36 | adal_component = ObjectCountAdalComponent(model_client, model_kwargs) 37 | trainer = adal.Trainer(adaltask=adal_component) 38 | trainer.diagnose(dataset=trainset, split="train") 39 | trainer.diagnose(dataset=valset, split="val") 40 | trainer.diagnose(dataset=testset, split="test") 41 | 42 | 43 | if __name__ == "__main__": 44 | from use_cases.config import ( 45 | gpt_3_model, 46 | ) 47 | 48 | # from use_cases.question_answering.bhh_object_count.prepare_trainer import ( 49 | # TGDWithEvalFnLoss, 50 | # ) 51 | 52 | # from adalflow.optim.trainer.trainer import Trainer 53 | 54 | # trainset, valset, testset = load_datasets(max_samples=10) 55 | # adaltask = TGDWithEvalFnLoss( 56 | # task_model_config=llama3_model, 57 | # backward_engine_model_config=llama3_model, 58 | # optimizer_model_config=llama3_model, 59 | # ) 60 | 61 | # trainer = Trainer(adaltask=adaltask) 62 | # diagnose = trainer.diagnose(train_dataset=trainset) 63 | # print(diagnose) 64 | 65 | # Diagnostic results run on trainer set, with all inputs and outputs tracked in ckpt/TGDWithEvalFnLoss/llm_counter_call 66 | 67 | diagnose(**gpt_3_model) 68 | -------------------------------------------------------------------------------- /use_cases/question_answering/gsm8k/task.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Union 2 | import re 3 | import adalflow as adal 4 | 5 | template = r""" 6 | {{system_prompt}} 7 | 8 | 9 | {{input_str}} 10 | 11 | """ 12 | 13 | system_prompt_start = "You will answer a reasoning question. Think step by step. The last line of your response should be of the following format: 'Answer: $VALUE' where VALUE is a numerical value." 14 | 15 | 16 | @adal.func_to_data_component 17 | def parse_integer_answer(answer: str) -> str: 18 | try: 19 | numbers = re.findall(r"\d+", answer) 20 | if numbers: 21 | answer = numbers[-1] 22 | else: 23 | answer = "" 24 | except ValueError: 25 | answer = "" 26 | 27 | return answer 28 | 29 | 30 | class GSM8KTask(adal.Component): 31 | def __init__(self, model_client: adal.ModelClient, model_kwargs: Dict): 32 | super().__init__() 33 | 34 | system_prompt = adal.Parameter( 35 | data=system_prompt_start, 36 | role_desc="To give task instruction to the language model in the system prompt", 37 | requires_opt=True, 38 | param_type=adal.ParameterType.PROMPT, 39 | ) 40 | self.generator = adal.Generator( 41 | model_client=model_client, 42 | model_kwargs=model_kwargs, 43 | prompt_kwargs={ 44 | "system_prompt": system_prompt, 45 | }, 46 | template=template, 47 | output_processors=parse_integer_answer, 48 | use_cache=True, 49 | ) 50 | 51 | def bicall( 52 | self, question: str, id: str = None 53 | ) -> Union[adal.GeneratorOutput, adal.Parameter]: 54 | output = self.generator(prompt_kwargs={"input_str": question}, id=id) 55 | return output 56 | 57 | 58 | if __name__ == "__main__": 59 | from adalflow.utils import setup_env 60 | from adalflow.datasets.gsm8k import GSM8K 61 | 62 | setup_env() 63 | 64 | from use_cases.config import gpt_3_model 65 | 66 | task = GSM8KTask(**gpt_3_model) 67 | 68 | train_dataset = GSM8K(split="train", size=10) 69 | 70 | print("example: ", train_dataset[0]) 71 | 72 | output = task(question=train_dataset[0].question) 73 | print("output: ", output) 74 | -------------------------------------------------------------------------------- /use_cases/rag/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/rag/__init__.py -------------------------------------------------------------------------------- /use_cases/rag/bootstrap_weak_model.py: -------------------------------------------------------------------------------- 1 | from adalflow.components.model_client.groq_client import GroqAPIClient 2 | import adalflow as adal 3 | 4 | # from adalflow.utils import get_logger 5 | 6 | # get_logger(level="DEBUG") 7 | 8 | 9 | rag_template = r""" 10 | You are a helpful assistant. 11 | 12 | Your task is to answer the query that may or may not come with context information. 13 | When context is provided, you should stick to the context and less on your prior knowledge to answer the query. 14 | 15 | 16 | 17 | {{input_str}} 18 | 19 | {% if context_str %} 20 | 21 | {{context_str}} 22 | 23 | {% endif %} 24 | 25 | """ 26 | adal.setup_env() 27 | llama3_model = { 28 | "model_client": GroqAPIClient(), 29 | "model_kwargs": { 30 | "model": "llama-3.1-8b-instant", 31 | }, 32 | } 33 | 34 | 35 | generator = adal.Generator( 36 | **llama3_model, 37 | template=rag_template, 38 | ) 39 | 40 | prompt_kwargs = { 41 | "input_str": "where is brian?", 42 | "context_str": "Brian is in the kitchen.", 43 | } 44 | 45 | output = generator(prompt_kwargs=prompt_kwargs) 46 | print(output) 47 | -------------------------------------------------------------------------------- /use_cases/rag/build/README.md: -------------------------------------------------------------------------------- 1 | There are different patterns to build a RAG. 2 | 3 | 1. RAG with separate data process pipeline and a RAG task pipeline. 4 | This fits into a scenario where there is lots of data in production database, and we preprocess the data to embeddings and then we build a RAG task pipeline that retrieves context in multiple stages. 5 | 6 | 2. RAG with dynamic data access. And cache the embedding dynamically in a local storage. 7 | -------------------------------------------------------------------------------- /use_cases/rag/simple_rag.yaml: -------------------------------------------------------------------------------- 1 | vectorizer: 2 | batch_size: 100 3 | model_kwargs: 4 | model: text-embedding-3-small 5 | dimensions: 256 6 | encoding_format: float 7 | 8 | retriever: 9 | top_k: 2 10 | 11 | generator: 12 | model: gpt-3.5-turbo 13 | temperature: 0.3 14 | stream: false 15 | 16 | text_splitter: 17 | split_by: sentence 18 | chunk_size: 1 19 | chunk_overlap: 0 20 | -------------------------------------------------------------------------------- /use_cases/tracing/trace_generator.py: -------------------------------------------------------------------------------- 1 | from adalflow.core.generator import Generator 2 | from adalflow.core.component import Component 3 | 4 | from adalflow.components.model_client import GroqAPIClient 5 | from adalflow.tracing.decorators import trace_generator_states, trace_generator_call 6 | 7 | 8 | @trace_generator_states() 9 | @trace_generator_call(error_only=False) 10 | class SimpleQA(Component): 11 | def __init__(self): 12 | super().__init__() 13 | self.generator = Generator( 14 | model_client=GroqAPIClient(), 15 | model_kwargs={"model": "llama3-8b-8192"}, 16 | preset_prompt_kwargs={ 17 | "task_desc_str": "You are a helpful assistant and with a great sense of humor. changes", 18 | }, 19 | trainable_params=[ 20 | "task_desc_str" 21 | ], # 1 we need to clearly define which is trainable. 22 | ) 23 | self.generator2 = Generator( 24 | model_client=GroqAPIClient(), 25 | model_kwargs={"model": "llama3-8b-8192"}, 26 | preset_prompt_kwargs={ 27 | "task_desc_str": "You are the second generator.", 28 | }, 29 | ) 30 | 31 | def call(self, query: str) -> str: 32 | return self.generator2.call(prompt_kwargs={"input_str": query}) 33 | 34 | 35 | if __name__ == "__main__": 36 | from adalflow.utils import get_logger 37 | 38 | get_logger(enable_file=False, level="DEBUG") 39 | log = get_logger(__name__, level="INFO") 40 | simple_qa = SimpleQA() 41 | log.info(simple_qa) 42 | states = simple_qa.state_dict() # only prameters 43 | print(f"states: {states}") 44 | 45 | print("show the system prompt") 46 | simple_qa.generator.print_prompt() 47 | records = simple_qa.generator_call_logger.load("generator") 48 | print(f"records: {records}") 49 | print("Answer:") 50 | print(simple_qa.call("What is the capital of France?")) 51 | -------------------------------------------------------------------------------- /use_cases/unsorted/llm_as_retriever.py: -------------------------------------------------------------------------------- 1 | from adalflow.core.types import Document 2 | 3 | from adalflow.components.retriever import LLMRetriever 4 | from adalflow.components.model_client import OpenAIClient 5 | 6 | 7 | def test_llm_retriever(): 8 | # TODO: directly pass Generator class is more intuitive than the generator_kwargs 9 | 10 | retriever = LLMRetriever( 11 | top_k=1, model_client=OpenAIClient, model_kwargs={"model": "gpt-3.5-turbo"} 12 | ) 13 | print(retriever) 14 | documents = [ 15 | Document(text="Paris is the capital of France."), 16 | Document(text="Berlin is the capital of Germany."), 17 | ] 18 | retriever.build_index_from_documents(documents) 19 | retriever.print_prompt() 20 | 21 | response = retriever("What do you know about Paris?") 22 | print(response) 23 | 24 | 25 | if __name__ == "__main__": 26 | test_llm_retriever() 27 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | from adalflow.core.generator import Generator 5 | from adalflow.core.component import Component 6 | from adalflow.components.model_client import OpenAIClient 7 | from adalflow.components.model_client import GroqAPIClient 8 | from adalflow.components.model_client import AnthropicAPIClient 9 | 10 | 11 | class SimpleQA(Component): 12 | r""" 13 | User-defined component who wants to switch between providers like OpenAI and Groq. 14 | """ 15 | 16 | def __init__( 17 | self, provider: str = "openai", model_kwargs: dict = {"model": "gpt-3.5-turbo"} 18 | ): 19 | super().__init__() 20 | if provider == "openai": 21 | 22 | model_client = OpenAIClient() 23 | elif provider == "groq": 24 | 25 | model_client = GroqAPIClient() 26 | elif provider == "anthropic": 27 | 28 | model_client = AnthropicAPIClient() 29 | else: 30 | raise ValueError(f"Unknown provider: {provider}") 31 | self.generator = Generator(model_client=model_client, model_kwargs=model_kwargs) 32 | self.generator.print_prompt() 33 | 34 | def call(self, query: str) -> str: 35 | return self.generator({"input_str": query}) 36 | 37 | async def acall(self, query: str) -> str: 38 | return await self.generator.acall({"input_str": query}) 39 | 40 | 41 | if __name__ == "__main__": 42 | query = "What is the capital of France?" 43 | queries = [query] * 10 44 | 45 | providers = ["openai", "groq", "anthropic"] 46 | model_kwargs_list = [ 47 | {"model": "gpt-3.5-turbo"}, 48 | {"model": "llama3-8b-8192"}, 49 | {"model": "claude-3-opus-20240229", "max_tokens": 1000}, 50 | ] 51 | for provider, model_kwargs in zip(providers, model_kwargs_list): 52 | simple_qa = SimpleQA(provider=provider, model_kwargs=model_kwargs) 53 | print(simple_qa) 54 | t0 = time.time() 55 | print(simple_qa.call("What is the capital of France?")) 56 | t1 = time.time() 57 | print(f"Total time for 1 sync call: {t1 - t0} seconds") 58 | 59 | async def make_async_call(query: str) -> str: 60 | return await simple_qa.acall(query) 61 | 62 | async def main(): 63 | queries = ["What is the capital of France?"] * 10 64 | tasks = [make_async_call(query) for query in queries] 65 | 66 | start_time = time.time() 67 | _ = await asyncio.gather(*tasks) 68 | end_time = time.time() 69 | 70 | print(f"Total time for 10 async calls: {end_time - start_time} seconds") 71 | 72 | # Execute the asynchronous function 73 | asyncio.run(main()) 74 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_anthropic.py: -------------------------------------------------------------------------------- 1 | """ 2 | We just need to very basic generator that can be used to generate text from a prompt. 3 | """ 4 | 5 | from adalflow.core.generator import Generator 6 | from adalflow.core.component import Component 7 | 8 | from adalflow.components.model_client import AnthropicAPIClient 9 | 10 | 11 | class SimpleQA(Component): 12 | def __init__(self): 13 | super().__init__() 14 | self.generator = Generator( 15 | model_client=AnthropicAPIClient(), 16 | model_kwargs={"model": "claude-3-opus-20240229", "max_tokens": 1000}, 17 | prompt_kwargs={ 18 | "task_desc_str": "You are a helpful assistant and with a great sense of humor." 19 | }, 20 | ) 21 | 22 | def call(self, query: str) -> str: 23 | return self.generator.call(prompt_kwargs={"input": query}) 24 | 25 | 26 | if __name__ == "__main__": 27 | simple_qa = SimpleQA() 28 | print(simple_qa) 29 | print("show the system prompt") 30 | simple_qa.generator.print_prompt() 31 | print(simple_qa.call("What is the capital of France?")) 32 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_google.py: -------------------------------------------------------------------------------- 1 | """ 2 | We just need to very basic generator that can be used to generate text from a prompt. 3 | """ 4 | 5 | from adalflow.core.generator import Generator 6 | from adalflow.core.component import Component 7 | 8 | from adalflow.components.model_client import GoogleGenAIClient 9 | 10 | 11 | class SimpleQA(Component): 12 | def __init__(self): 13 | super().__init__() 14 | self.generator = Generator( 15 | model_client=GoogleGenAIClient(), 16 | model_kwargs={"model": "gemini-1.5-pro-latest"}, 17 | preset_prompt_kwargs={ 18 | "task_desc_str": "You are a helpful assistant and with a great sense of humor." 19 | }, 20 | ) 21 | 22 | def call(self, query: str) -> str: 23 | return self.generator.call(prompt_kwargs={"input": query}) 24 | 25 | 26 | if __name__ == "__main__": 27 | simple_qa = SimpleQA() 28 | print(simple_qa) 29 | print("show the system prompt") 30 | simple_qa.generator.print_prompt() 31 | print(simple_qa.call("What is the capital of France?")) 32 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_groq.py: -------------------------------------------------------------------------------- 1 | from adalflow.core.generator import Generator 2 | from adalflow.core.component import Component 3 | 4 | from adalflow.components.model_client import GroqAPIClient 5 | 6 | 7 | class SimpleQA(Component): 8 | def __init__(self): 9 | super().__init__() 10 | self.generator = Generator( 11 | model_client=GroqAPIClient(), # other options OpenAIClient, AnthropicClient, GoogleGenAIClient, 12 | model_kwargs={"model": "llama3-8b-8192"}, 13 | preset_prompt_kwargs={ 14 | "task_desc_str": "You are a helpful assistant and with a great sense of humor." 15 | }, 16 | trainable_params=[ 17 | "task_desc_str" 18 | ], # 1 we need to clearly define which is trainable. 19 | ) 20 | 21 | def call(self, query: str) -> str: 22 | return self.generator.call(prompt_kwargs={"input_str": query}) 23 | 24 | 25 | if __name__ == "__main__": 26 | simple_qa = SimpleQA() 27 | print(simple_qa) 28 | states = simple_qa.state_dict() # only prameters 29 | print(f"states: {states}") 30 | print("show the system prompt") 31 | simple_qa.generator.print_prompt() 32 | print("Answer:") 33 | print(simple_qa.call("What is the capital of France?")) 34 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_memory.py: -------------------------------------------------------------------------------- 1 | # TODO: We need an example to demonstrate how to use the memory component in the genertor. 2 | 3 | 4 | # from adalflow.core.component import Component 5 | # from adalflow.core.memory import Memory 6 | 7 | # from adalflow.components.model_client import OpenAIClient 8 | 9 | 10 | # class SimpleDialog(Component): 11 | # def __init__(self): 12 | # super().__init__() 13 | # model_kwargs = {"model": "gpt-3.5-turbo"} 14 | # task_desc_str = "You are a helpful assistant." 15 | # self.generator = Generator( 16 | # model_client=OpenAIClient(), 17 | # model_kwargs=model_kwargs, 18 | # preset_prompt_kwargs={"task_desc_str": task_desc_str}, 19 | # ) 20 | # self.chat_history = Memory() 21 | # self.generator.print_prompt() 22 | 23 | # def chat(self) -> str: 24 | # print("Welcome to SimpleQA. You can ask any question. Type 'exit' to end.") 25 | # while True: 26 | # user_input = input("You: ") 27 | # # 28 | # if user_input.lower() == "exit": 29 | # print("Goodbye!") 30 | # break 31 | # chat_history_str = self.chat_history() 32 | # response = self.generator( 33 | # prompt_kwargs={ 34 | # "chat_history_str": chat_history_str, 35 | # "input": user_input, 36 | # }, 37 | # ) 38 | # # save the user input and response to the memory 39 | # self.chat_history.add_dialog_turn( 40 | # user_query=user_input, assistant_response=response 41 | # ) 42 | # """ 43 | # Most components mush have a __call__ method in order to be chained together with other component in the data pipeline. 44 | # From the memory management, it is difficult to just chain them together. 45 | # This is similar to the retrieval. This additional step is to manage the exteral db like 46 | # data injection. Retrieving can be chained such as we use self.chat_history() to get the chat history. 47 | # """ 48 | # print(f"Assistant: {response}") 49 | 50 | # # a class to have a multiple turns and take user input 51 | 52 | 53 | # if __name__ == "__main__": 54 | # simple_qa = SimpleDialog() 55 | # print(simple_qa) 56 | # print(simple_qa.chat()) 57 | -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_stream.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SylphAI-Inc/AdalFlow/b43a86611ffaecc9d016157c4a46b311f066ec12/use_cases/unsorted/simple_qa_stream.py -------------------------------------------------------------------------------- /use_cases/unsorted/simple_qa_trainable.py: -------------------------------------------------------------------------------- 1 | from adalflow.core.generator import Generator 2 | from adalflow.core.component import Component 3 | 4 | from adalflow.components.model_client import GroqAPIClient 5 | 6 | 7 | class SimpleQA(Component): 8 | def __init__(self): 9 | super().__init__() 10 | self.generator = Generator( 11 | model_client=GroqAPIClient, # other options OpenAIClient, AnthropicClient, GoogleGenAIClient, 12 | model_kwargs={"model": "llama3-8b-8192"}, 13 | preset_prompt_kwargs={ 14 | "task_desc_str": "You are a helpful assistant and with a great sense of humor." 15 | }, 16 | trainable_params=[ 17 | "task_desc_str" 18 | ], # 1 we need to clearly define which is trainable. 19 | ) 20 | 21 | def init_parameters(self): 22 | self.generator.task_desc_str.update_value( 23 | "You are a helpful assistant and with a great sense of humor." 24 | ) 25 | 26 | def call(self, query: str) -> str: 27 | return self.generator.call(input=query) 28 | 29 | 30 | if __name__ == "__main__": 31 | # TODO: convert some of this code to pytest for states 32 | simple_qa = SimpleQA() 33 | print(simple_qa) 34 | simple_qa.init_parameters() 35 | states = simple_qa.state_dict() 36 | print(f"states: {states}") # conv1.weight, conv1.bias, fc1.weight, fc1.bias 37 | 38 | simple_qa_2 = SimpleQA() 39 | states_before = simple_qa_2.state_dict() 40 | print(f"states_before: {states_before}") 41 | simple_qa_2.load_state_dict(states) 42 | states_2 = simple_qa_2.state_dict() 43 | print(f"states_2: {states_2}") 44 | 45 | print("show the system prompt") 46 | simple_qa.generator.print_prompt() 47 | print("Answer:") 48 | print(simple_qa.call("What is the capital of France?")) 49 | -------------------------------------------------------------------------------- /use_cases/unsorted/use_embedder.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from typing import List, Any 3 | 4 | from adalflow.core.embedder import Embedder 5 | from adalflow.core.component import Component 6 | from adalflow.components.model_client import OpenAIClient 7 | 8 | 9 | class SimpleEmbedder(Component): 10 | """ 11 | The embedder takes a list of queries leverage the api's batch processing capabilities 12 | """ 13 | 14 | def __init__(self): 15 | super().__init__() 16 | model_kwargs = { 17 | "model": "text-embedding-3-small", 18 | "dimensions": 256, 19 | "encoding_format": "float", 20 | } 21 | self.embedder = Embedder(model_client=OpenAIClient(), model_kwargs=model_kwargs) 22 | 23 | def call(self, queries: List[str]) -> Any: 24 | return self.embedder(input=queries) 25 | 26 | async def acall(self, queries: List[str]) -> Any: 27 | return await self.embedder.acall(input=queries) 28 | 29 | 30 | if __name__ == "__main__": 31 | import time 32 | 33 | queries = ["What is the capital of France?"] * 10 34 | 35 | embedder = SimpleEmbedder() 36 | print(embedder) 37 | t0 = time.time() 38 | print(embedder.call(queries)) 39 | t1 = time.time() 40 | print(f"Total time for 1 sync call: {t1 - t0} seconds") 41 | 42 | async def make_async_call(query: str) -> str: 43 | return await embedder.acall(query) 44 | 45 | async def main(): 46 | async_queries = [queries] * 10 47 | tasks = [make_async_call(query) for query in async_queries] 48 | 49 | start_time = time.time() 50 | results = await asyncio.gather(*tasks) 51 | print(results) 52 | end_time = time.time() 53 | 54 | print(f"Total time for 10 async calls: {end_time - start_time} seconds") 55 | 56 | # Execute the asynchronous function 57 | asyncio.run(main()) 58 | --------------------------------------------------------------------------------