{"id":24020153,"url":"https://github.com/appl-team/appl","last_synced_at":"2025-09-14T20:31:48.021Z","repository":{"id":238173356,"uuid":"769405173","full_name":"appl-team/appl","owner":"appl-team","description":"🍎APPL: A Prompt Programming Language. Seamlessly integrate LLMs with programs.","archived":false,"fork":false,"pushed_at":"2025-01-04T17:36:15.000Z","size":9275,"stargazers_count":216,"open_issues_count":0,"forks_count":2,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-01-04T18:30:11.432Z","etag":null,"topics":["developer-tools","llm","prompt-language","python"],"latest_commit_sha":null,"homepage":"https://appl-team.github.io/appl/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appl-team.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"code_of_conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-09T01:43:37.000Z","updated_at":"2025-01-04T17:36:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"1a711765-f193-47db-82e9-dbd1e923c9d2","html_url":"https://github.com/appl-team/appl","commit_stats":null,"previous_names":["appl-team/appl"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appl-team%2Fappl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appl-team%2Fappl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appl-team%2Fappl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appl-team%2Fappl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appl-team","download_url":"https://codeload.github.com/appl-team/appl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233026988,"owners_count":18613583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-tools","llm","prompt-language","python"],"created_at":"2025-01-08T12:00:46.208Z","updated_at":"2025-01-08T12:02:02.327Z","avatar_url":"https://github.com/appl-team.png","language":"Python","funding_links":[],"categories":["A01_文本生成_文本对话"],"sub_categories":["大语言对话模型及数据"],"readme":"# 🍎APPL: A Prompt Programming Language\n\n[![version](https://img.shields.io/pypi/v/applang.svg)](https://pypi.python.org/pypi/applang)\n[![python](https://img.shields.io/badge/Python-3.9%2B-blue.svg?style=flat\u0026logo=python\u0026logoColor=white)](https://www.python.org)\n[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white)](https://pre-commit.com/)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://mit-license.org/)\n[![Discord](https://img.shields.io/badge/discord-orange)](https://discord.gg/q3x4Qwgj29)\n[![arXiv](http://img.shields.io/badge/cs.AI-arXiv%3A2406.13161-B31B1B.svg?logo=arxiv\u0026logoColor=red)](https://arxiv.org/abs/2406.13161)\n\n**APPL** is A Prompt Programming Language that extends Python to provide a Natural, Intuitive, Convenient, and Efficient (NICE) way to utilize Large Language Models (LLMs) such as GPT in your program. We believe Language Model will be an essential part of future software that help achieves more than what we can do today, and APPL is a step towards this future that seamlessly integrates programs and LLMs.\n\n\u003cvideo style=\"width: 100%\" src=\"https://github.com/appl-team/appl/assets/12556773/5d75d3db-1b1c-48c9-97ec-e9d72a387e49\" type=\"video/mp4\" controls\u003e\u003c/video\u003e\n\n## Key Features\n- **Readability and maintainability via seamless integration with Python.**  APPL seamlessly embeds natural language prompts into Python programs, maintaining prompts' readability while inheriting modularity, reusability, dynamism and the ecosystem from the host programming language.\n- **Flexible prompt engineering.**  Except for allowing the utilization of Python control flows and the modularized decomposition of prompts, APPL offers prompt coding helpers to facilitate programming prompts in a modularized and maintainable way.\n- **Automatic parallelization via asynchronous computation.**  APPL schedules LLM calls asynchronously, leveraging potential independence among them to facilitate efficient parallelization. This offloads the burden of users to manage synchronization manually, with almost no extra work.\n- **Smooth tool calling integration.**  APPL provides intuitive ways to transform Python functions into tools that can be called by LLMs, making it easier for users to integrate existing Python libraries and functions with LLMs.\n- **Tracing and Failure Recovery.** APPL traces the execution of LLM calls and supports recovery from failures, which is essential for debugging and error handling in the LLM programming paradigm.\n- **More Features.** APPL has many more other features, such as an auto-continuation mechanism to continue the generation when the output token limit is exceeded.\n- **Integrations.** APPL also provides a unified interface for multiple LLM backends using [`litellm`](https://docs.litellm.ai/docs/), [llm observability](https://appl-team.github.io/appl/tutorials/7_tracing/#visualizing-the-trace) using [`langfuse`](https://github.com/langfuse/langfuse) and [`lunary`](https://github.com/lunary-ai/lunary), and many other features.\n\n## News\n* **[2024-12-16]**: APPL 0.2.0 is released with many new features! Please check the [release note](https://github.com/appl-team/appl/releases/tag/v0.2.0) for more details.\n* **[2024-07-12]**: We have improved our [tutorial](https://appl-team.github.io/appl/tutorials/). Please check them out for more detailed usage and examples.\n\u003c!-- and [cookbook](https://appl-team.github.io/appl/tutorials/) --\u003e\n\n## Quick Start\n\n### Installation\nYou can simply install APPL from PyPI using pip:\n```bash\npip install -U applang\n```\nMore installation options can be found in the [installation guide](https://appl-team.github.io/appl/install).\n\n### Setup\nYou need to set up API keys or your own LLM backends to interact with LLMs.\n\nIn this guide, we use OpenAI API as the default backend.\nYou can set your OpenAI API key in the `.env` file in the root directory of your project:\n```\nOPENAI_API_KEY=\u003cyour openai api key\u003e\n```\n\nor export it as an environment variable:\n\n```bash\nexport OPENAI_API_KEY=\u003cyour openai api key\u003e\n```\n\nFor setting up other backends, enabling tracing and recovering from traces, please refer to the [setup guide](https://appl-team.github.io/appl/setup).\n\n### Hello World\n\nTo begin, let's create a simple function that uses LLM to respond to a greeting.\n\n```python\nfrom appl import gen, ppl\n\n@ppl  # the @ppl decorator marks the function as an `APPL function`\ndef greeting(name: str):\n    f\"Hello World! My name is {name}.\"  # Add text to the prompt\n    return gen()  # call the default LLM with the current prompt\n\nprint(greeting(\"APPL\"))  # call `greeting` as a normal Python function\n```\n\nThe prompt for the generation is:\n```\nHello World! My name is APPL.\n```\n\nThe output will look like\n```\nNice to meet you, APPL!\n```\n\nIn this example, the `@ppl` decorator (`@` stands for `a` here) marks the `hello_world` function as an *APPL function*. Within such a function, the standalone string `f\"Hello World! My name is {name}.\"` is added to the prompt, and the `gen()` function calls LLM to generate responses using the current prompt. Moreover, explicitly appending the prompt is also supported using `grow`:\n\n```python\nfrom appl import gen, grow, ppl\n\n@ppl  # the @ppl decorator marks the function as an `APPL function`\ndef greeting(name: str):\n    grow(f\"Hello World! My name is {name}.\")  # grow the prompt\n    return gen()  # call the default LLM with the current prompt\n\nprint(greeting(\"APPL\"))  # call `greeting` as a normal Python function\n```\n\n### Question Answering\n\nLet's then implement a question-answering system using APPL. In this example, the APPL program answers multiple questions about a quotation by first extracting the author's name (inspired by [this cookbook](https://cookbook.openai.com/articles/how_to_work_with_large_language_models)). [Here](https://colab.research.google.com/drive/1khZcleOrdLOWtUB4EMEQCjGA1vBaARI9) is a runnable Colab notebook of this example.\n\n```python linenums=\"1\" hl_lines=\"5 10 11 13\"\nfrom appl import AIRole, gen, ppl\n\n@ppl(ctx=\"copy\")  # copy the context from caller\ndef get_answer(question: str):\n    question  # append to the prompt\n    return gen()  # return as a future object\n\n@ppl  # marks APPL function\ndef answer_questions(quotation: str, questions: list[str]):\n    \"Extract the name of the author from the quotation below and answer questions.\"\n    quotation  # append to the prompt\n    with AIRole():  # assistant message\n        f\"The name of the author is {gen(stop='.')}\"  # specify the prefix\n    return [get_answer(q) for q in questions]  # parallelize calls\n\nquotation = '\"Simplicity is the ultimate sophistication.\" -- Leonardo da Vinci'\nquestions = [\n    \"In what era did the author live?\",\n    # more questions can be added here\n]\nfor ans in answer_questions(quotation, questions):\n    print(ans)\n```\n\nThe resulting conversation for the first question would look like (generated responses are in **bold**):\n\n| Role        | Message                                                                                                                                            |\n| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |\n| *User*      | Extract the name of the author from the quotation below and answer questions.\u003cbr\u003e\"Simplicity is the ultimate sophistication.\" -- Leonardo da Vinci |\n| *Assistant* | The name of the author is **Leonardo da Vinci.**                                                                                                   |\n| *User*      | In what era did the author live?                                                                                                                   |\n| *Assistant* | **Leonardo da Vinci lived during the Renaissance era.**                                                                                            |\n\nIn *APPL functions*, [expression statements](https://docs.python.org/3/reference/simple_stmts.html#expression-statements) are captured as prompts [based on the type of its value](https://appl-team.github.io/appl/tutorials/appendix/prompt_capture/). Notably, the f-string is processed part by part, so the `gen` function inside the f-string intuitively uses the contents before that. In this example, `The name of the author is ` serves as a prefix to guide the completion of the author's name.\n\nAfter the author's name is extracted, the `get_answer` function is called multiple times in parallel to answer the questions, with the context being copied (detailed in [context-management](#context-management)), demonstrating the automatic parallelization feature of APPL.\n\nOn the other hand, this is a pretty long Langchain code that implements the same functionality, where you can feel the inflexibility of using prompt templates:\n```python linenums=\"1\" \nfrom concurrent.futures import ThreadPoolExecutor\nfrom typing import List\n\nfrom dotenv import load_dotenv\nfrom langchain_core.output_parsers import StrOutputParser\nfrom langchain_core.prompts import ChatPromptTemplate\nfrom langchain_openai import ChatOpenAI\n\nload_dotenv()\n\nllm = ChatOpenAI()\n\nmessages = [\n    (\n        \"user\",\n        \"Extract the name of the author from the quotation below:\\n{quotation}\",\n    ),\n    (\"assistant\", \"The name of the author is \"),\n]\nauthor_prompt = ChatPromptTemplate.from_messages(messages)\n\nmessages = messages[:1] + [\n    (\"assistant\", \"The name of the author is {author}\"),\n    (\"user\", \"{question}\"),\n]\nquestion_prompt = ChatPromptTemplate.from_messages(messages)\n\n\ndef answer_questions(quotation: str, questions: List[str]):\n    # First extract the author\n    author_chain = author_prompt | llm | StrOutputParser()\n    author = author_chain.invoke({\"quotation\": quotation})\n\n    # Create question answering chain\n    qa_chain = question_prompt | llm | StrOutputParser()\n\n    def answer_single_question(question):\n        return qa_chain.invoke(\n            {\"quotation\": quotation, \"author\": author, \"question\": question}\n        )\n\n    # Answer each question in parallel using map\n    with ThreadPoolExecutor() as executor:\n        return list(executor.map(answer_single_question, questions))\n\n\nquotation = '\"Simplicity is the ultimate sophistication.\" -- Leonardo da Vinci'\nquestions = [\n    \"In what era did the author live?\",\n    \"What is the most famous painting of the author?\",\n]\nprint(answer_questions(quotation, questions))\n```\n\n## RoadMap\n- [x] Default to exclude \"\"\"docstring\"\"\" from the prompt formation.\n- [x] Add supports for LLM logging and tracing platforms to inspect the traces.\n  - [x] Supported Lunary and Langfuse (open-source)\n- [ ] Allow directly working with prompts without `ppl` decorator.\n- [ ] Add more ... (contributions are welcome!)\n  - [ ] Examples and tutorials to demonstrate the usage\n  - [ ] Test cases to increase the coverage\n\n## Tutorial and Cookbook\nFor a more comprehensive tutorial, please refer to the [tutorial](https://appl-team.github.io/appl/tutorials).\n\n### Table of Contents\n- [Introduction](https://appl-team.github.io/appl/tutorials/intro)\n- [Getting Started](https://appl-team.github.io/appl/tutorials/1_get_started)\n- [Example: QA with LMs](https://appl-team.github.io/appl/tutorials/2_qa_example)\n- [APPL Function](https://appl-team.github.io/appl/tutorials/3_appl_function)\n- [Concurrent LM Calls](https://appl-team.github.io/appl/tutorials/4_concurrent)\n- [Tool Calls for LMs](https://appl-team.github.io/appl/tutorials/5_tool_calls)\n- [Prompt Coding Helpers](https://appl-team.github.io/appl/tutorials/6_prompt_coding)\n- [Using Tracing](https://appl-team.github.io/appl/tutorials/7_tracing)\n\n### Cookbook and Applications\nFor more detailed usage and examples, please refer to the [cookbook](https://appl-team.github.io/appl/cookbook).\n\nWe use APPL to reimplement popular LLM and prompting algorithms in [Reppl](https://github.com/appl-team/reppl), such as:\n* [Tree of Thoughts](https://github.com/princeton-nlp/tree-of-thought-llm) [[Re-implementation](https://github.com/appl-team/reppl/tree/main/tree-of-thoughts/)] [[APPL Example](examples/advanced/tree_of_thoughts/)]: deliberate problem solving with Large Language Models.\n\nWe use APPL to build popular LM-based applications, such as:\n* [Wordware's TwitterPersonality](https://twitter.wordware.ai/)[[APPL implementation](https://github.com/appl-team/TwitterPersonality)]: analyzes your tweets to determine your Twitter personality.\n\nWe use APPL to build small LLM-powered libraries, such as:\n* [AutoNaming](https://github.com/appl-team/AutoNaming): automatically generate names for experiments based on argparse arguments.\n* [ExplErr](https://github.com/appl-team/ExplErr): a library for error explanation with LLMs.\n\n## Working with Cursor (Experimental)\nWe provide [.cursorrules](https://github.com/appl-team/appl/blob/main/.cursorrules) to help you write APPL code with [Cursor](https://www.cursor.com/). You also setup the [Docs Symbol](https://docs.cursor.com/context/@-symbols/@-docs) with [APPL Docs](https://appl-team.github.io/appl/docs/). Thanks @xiumaoprompt for suggestion!\n\n## Citation and Acknowledgment\nIf you find APPL helpful, please consider citing our paper:\n```bibtex\n@article{dong2024appl,\n  title={APPL: A Prompt Programming Language for Harmonious Integration of Programs and Large Language Model Prompts},\n  author={Dong, Honghua and Su, Qidong and Gao, Yubo and Li, Zhaoyu and Ruan, Yangjun and Pekhimenko, Gennady and Maddison, Chris J and Si, Xujie},\n  journal={arXiv preprint arXiv:2406.13161},\n  year={2024}\n}\n```\n\nWe would like to thank the open-source community for their contributions, where we learned from or used these libraries in our project, including\n[instructor](https://github.com/jxnl/instructor),\n[LiteLLM](https://github.com/BerriAI/litellm),\n[LMQL](https://github.com/eth-sri/lmql),\n[Guidance](https://github.com/guidance-ai/guidance),\n[SGLang](https://github.com/sgl-project/sglang) and\n[autogen](https://github.com/microsoft/autogen).\n\nWe also notice that there are more projects coming out to push the boundaries of prompt programming, such as [ell](https://github.com/MadcowD/ell) and [mirascope](https://github.com/Mirascope/mirascope/).\n\n## License\nThis project is licensed under the terms of the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappl-team%2Fappl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappl-team%2Fappl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappl-team%2Fappl/lists"}